2👍
I’m not 100% what you’re trying to accomplish, but I think you’ve misunderstood how slots work.
Slots
The <slot>
element lets you distribute content into a component. Here is a small example:
Vue.component('child-component', {
template: '#child-component'
});
new Vue({
el: '#app',
data: { message: 'Hello I have been slotted' }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<div id="app">
<child-component>
{{ message }}
</child-component>
</div>
<template id="child-component">
<div>
<p>Above the slot</p>
<slot></slot>
<p>Below the slot</p>
</div>
</template>
Essentially, any html between the component tags gets put into the slot. You can read more about slots in the documentation here.
The Problem
You have tried to slot three moustache components into moustaches, but moustaches doesn’t have a slot.
Also, you have given the moustache components slots, but haven’t slotted anything in.
Solution #1
Add a slot to the moustaches
component. Because the moustache
components are empty divs, they will not show up on the page. Here is a working code snippet:
Vue.component('moustaches', {
template: '#moustaches',
data() {
return { moustaches: [] };
},
created() {
this.moustaches = this.$children;
}
});
Vue.component('moustache', {
template: '<div><slot></slot></div>',
props: {
name: { required: true },
img: { required: true},
selected: { default: false }
}
});
new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<div id="app">
<moustaches>
<moustache name="The Burgundy" img="/img/the-burgundy.jpg"></moustache>
<moustache name="The Borat" img="/img/the-borat.jpg"></moustache>
<moustache name="The Santana" img="/img/the-santana.jpg"></moustache>
</moustaches>
</div>
<template id="moustaches">
<div>
<ul class="list-inline">
<li v-for="moustache in moustaches">
<p>
<strong>@{{ moustache.name }}</strong>
</p>
<img width="300" height="200" :src="moustache.img">
<button
class="btn btn-primary"
:data-type="moustache.name"
>
Vote
</button>
</li>
</ul>
<slot></slot>
</div>
</template>
I do not recommend this approach, because you are using the slot only to pass data. Slots should be used to pass html, not data. It is a strange way of doing things and you’ll likely run into other bugs.
Solution #2
Instead of using a slot to pass data, you should be passing data via props. By moving the data out of the html, and into the parent component, we can get rid of all slots and the moustache
component entirely:
Vue.component('moustaches', {
template: '#moustaches',
props: ['moustaches'],
});
new Vue({
el: '#app',
data: {
moustaches: [
{ name: "The Burgundy", img: "/img/the-burgundy.jpg" },
{ name: "The Borat", img: "/img/the-borat.jpg" },
{ name: "The Santana", img: "/img/the-santana.jpg" },
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script>
<div id="app">
<moustaches :moustaches="moustaches"></moustaches>
</div>
<template id="moustaches">
<div>
<ul class="list-inline">
<li v-for="moustache in moustaches">
<p>
<strong>@{{ moustache.name }}</strong>
</p>
<img width="300" height="200" :src="moustache.img">
<button
class="btn btn-primary"
:data-type="moustache.name"
>
Vote
</button>
</li>
</ul>
</div>
</template>
0👍
The above poster kindly answered the question much better than I could but TL:DR answer is I was missing <slot></slot>
in the Moustaches component.
I just added it below the closing div and it worked.