4

I'm new to Vue.js and I'm having a bit of trouble using components with sub-components. I have the following .vue files

app.vue

<template>
  <section>
    <menu></menu>
    <h1>Create Your MIA</h1>
    <div id="board"></div>
    <slider>
      <skin></skin>
    </slider>
  </section>
</template>

slider.vue

<template>
  <div id="slider-panel">
    <h3>{{* heading}}</h3>
    <div class="slider">
      <slot>
        Some content
      </slot>
    </div>
  </div>
</template>

<script>
import skin from "./skin";
  export default {
    components: {
      skin: skin
    }
  };
</script>

skin.vue

<template>
    <div v-for="colour in colours">
      <div :style="{ backgroundColor: colour }">
        <img src="../assets/images/MIA.png"/>
      </div>
    </div>
</template>

<script>
  export default {
    data() {
      return {
        heading: "Choose Skin Tone"
      };
    }
  };
</script>

I'm trying to load the skin sub component into the component. Everything works well except for the skin sub component as it doesn't get compiled. I do not get any compile or vue related errors though. I also wanted to be able to have several instances of the slider component like this

app.vue

<template>
  <section>
    <menu></menu>
    <h1>Create Your MIA</h1>
    <div id="board"></div>
    <slider>
      <skin></skin>
    </slider>
    <slider>
      <foo></foo>
    </slider>
    <slider>
      <bar></bar>
    </slider>
  </section>
</template>

I'm not sure what I am doing wrong.

2 Answers 2

9

I'm not 100% sure of what you want to achieve here, but to compile a component inside a component, you need to add the child component inside the parent's template, like this:

Slider.vue (I've simplified the structure):

<template>
  <div id="slider-panel">
    <h3>{{* heading}}</h3>
    <skin></skin>
  </div>
</template>
<script>
import skin from './skin'
export default {
  components : {
    'skin': skin
  }
}
</script>

App.vue:

<template>
  <section>
    <menu></menu>
    <h1>Create Your MIA</h1>
    <div id="board"></div>
    <slider></slider>
  </section>
</template>

Actually, if you add skin in the app's template inside of adding it in the slider component template, it gets included (and rendered) assuming that its scope is app, not slider. In order to add skin inside slider scope, it needs to be added to slider's template. Check this: https://vuejs.org/guide/components.html#Compilation-Scope

Some other things:

Good luck!

Update:

If you want the slider component to be content agnostic and be able to insert anything you want inside it, you have two options (that I can think of):

  1. Remove all the logic from the slider component and make skin a descendant from app. Then use slots in the slider component, as follows:

Slider.vue:

<template>
  <div id="slider-panel">
    <h3>{{* heading}}</h3>
    <slot></slot>
  </div>
</template>
<script>
export default {}
</script>

App.vue:

<template>
  <section>
    <menu></menu>
    <h1>Create Your MIA</h1>
    <div id="board"></div>
    <slider>
      <skin></skin>
    </slider>
  </section>
</template>
<script>
import skin from './skin'
export default {
  skin: skin
}
</script>
  1. If you know that the slider will always have a closed set of components inside, you can use dynamic components: https://vuejs.org/guide/components.html#Dynamic-Components
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the suggestion. I separated the skin component and the slider component because I wanted to be able to "reuse" the slider components and swap out the skin for some something else e.g. <slider><foo></foo></slider> Would I be able to complies this without duplicating the slider-component?
Why did you say a "descendant" of "app.vue" and not a "child component"?
No reason, but you are right, "child component" makes more sense.
Hmm... I'm looking over the code and I don't think it will work as I want to run multiple slider-components in the app.vue component
This should be the accepted answer. +1 for the ... hyphen-separated name for the components suggestion.
2

After some research I found this which refers to a is= attribute that will transclude the sub-component template

so in app.vue

<slider-component>
      <div is="skin-component" v-for="colour in colours"></div>
    </slider-component>

and then add child components

2 Comments

That's actually a good idea. Let me know if it works as expected.
it did @HectorLorenzo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.