Nabab
Nabab

Reputation: 2654

VueJS: Analyze content of a slot with components before they are mounted

Let's say we have a component <my-cp :list="list"></my-cp>

With this kind of template:

<div class="container">
  <slot></slot> 
  <my-cp2 v-for="li in list" :my-data="li.data"></my-cp2>
</div>

My question: Is it possible to initialise my component my-cp either with list as an array or using HTML?

I mean having both possibilities. In this case, the HTML would look like this:

<my-cp>
  <my-cp2 my-data="foo">
  <my-cp2 my-data="bar">
</my-cp>

I am trying to analyze the content of the slot before it is mounted but it seems I can only access the element once the child component is already mounted.

Upvotes: 3

Views: 1639

Answers (1)

Bert
Bert

Reputation: 82489

Put your default content inside the slot in your component. If the user adds slot content, their content will show. Otherwise, the slot content will show.

<div class="container">
  <slot>
    <my-cp2 v-for="li in list" :my-data="li.data"></my-cp2>
  </slot> 
</div>

Here is an example.

Edit

After further discussion in the comments, I believe I understand what you want to do. To clarify for future readers, as I understand it, @Nabab wants to be able to initialize his component using either data coming from a property, or from components rendered in the HTML in the slot for the component. Additionally the component should be able to modify the existing data to add more items to it's list.

You can do this using a render function.

Vue.component("my-cp",{
  props:["list"],
  data(){
    return {
      internalList: this.list
    }
  },
  render(h){
    let workingList = []

    // Examine the default slot, and if there are any parse
    // them and add the data to the workingList
    if (this.$slots.default){
      for (node of this.$slots.default)
        // May want to check here if the node is a myCp2,
        // otherwise, grab the data
         workingList.push(node.componentOptions.propsData.myData)
    }

    // Add any items that came from the property/internal data
    workingList = workingList.concat(this.internalList)

    // Create a list of myCp2 vnodes with the correct data
    const list = workingList.map(n => h(myCp2, {props:{myData:n}}))

    // Create a button to add list items
    const btn = h("button", {on:{click:() => this.internalList.push({bar: true})}}, "Add")

    //Render
    return h("div", [list, btn])
  },
})

Here is an example.

Upvotes: 4

Related Questions