Kendall
Kendall

Reputation: 5245

Components and Sub components

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.

Upvotes: 4

Views: 27089

Answers (2)

Kendall
Kendall

Reputation: 5245

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

Upvotes: 2

user900362
user900362

Reputation:

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

Upvotes: 9

Related Questions