I have the following code, I am using two components, one called Moustaches and the other called Moustache
I am trying to show the data from Moustache inside Moustaches using a v-for
I am not getting any data or any errors, the Moustaches html is showing in the source code but not the Moustache data.
HTML
<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>
JS
Vue.component('moustaches', {
template: `
<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>
`,
mounted() {
console.log(this.$children);
},
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'
});
Rendered HTML
<div><ul class="list-inline"></ul></div>
I'm not 100% what you're trying to accomplish, but I think you've misunderstood how slots work.
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.
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.
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.
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>