If i have a component with a single slot and instead of just rendering all of it's children I want to wrap each element, I do something like this:
Vue.component('MyElement', {
render: function(createElement){
for (let i = 0; i < this.$slots.default.length; i++) {
//create a wrapper element
let wrappedElement = createElement("div", {}, this.$slots.default[i]);
// replace the current element in this slot, with the wrapped element
this.$slots.default[i] = wrappedElement;
}
return createElement("div", this.$slots.default);
}
}
Used like this:
<MyElement ref="myElement">
<p>Item 1</p>
<p>Item 2</p>
</MyElement>
Which ends up looking like this
<div>
<div>
<p>Item 1</p>
</div>
<div>
<p>Item 2</p>
</div>
</div>
Up to this point everything is great.
Now when I'd like to insert another <p>
element into <MyElement>
using
// get reference to <MyElement>
const myElement = this.$refs["myElement"];
// create a new element
var newElement = document.createElement("div");
newElement.innerText = "Hiya";
myElement .$el.appendChild(newElement);
The new element won't get wrapped, because render is not invoked again, how can I take full control of rendering for each child in my slot? or is there a better when to append children programatically into a component?
Thanks
If you could consider creating a component
for the Items. So that when you want to add a new item, you could just create a method
which will invoke the item component.
I made a Code Snippet for this example.
Vue.component('MyElement', {
template: '#element-container',
});
Vue.component('MyElementItem', {
template: '#element-item',
props: {
innerText: {
type: String,
default: '',
}
}
});
new Vue({
el: '#app',
data() {
return {
items: ['Item 1', 'Item 2', 'Item 3'],
}
},
method: {
// you can add a method that will add more items, then the MyElementItem component will be invoked.
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-element>
<my-element-item v-for="(item, index) in items" :key="index" :inner-text="item" />
</my-element>
</div>
<script type="text/x-template" id="element-container">
<div>
<slot></slot>
</div>
</script>
<script type="text/x-template" id="element-item">
<div>
<p>{{ innerText }}</p>
</div>
</script>