2
votes

I just learnt about slot today on Vue official tutorial. As I read through, I came across this example on scoped slot: https://vuejs.org/v2/guide/components.html#Scoped-Slots.

I experimented a little by adding an input field to each item.

Parent:

<my-list :items="items"> 
    <template slot="item" scope="props">
        <li class="my-fancy-item">{{ props.text }}</li>
    </template>
</my-list>

Child template:

  <ul>
     <slot name="item" v-for="item in items" :text="item.text">
     </slot>
     <div> // this will appear at the end of list
         <input v-model = "message"> 
     </div>
     <p>{{message}}</p>
  </ul>

My first attempt was to move the input to the parent scope and called a child function by passing into it the index and input value using props to modify the original array. It worked as intended.

Another attempt is to do binding on parent scope but it won't work because parent scope can't see child property: https://vuejs.org/v2/guide/components.html#Compilation-Scope

What is the best way to insert this input so that it will appear in every item and still be able to bind input to child property?

1
Where does message come from? Are you really wanting to have an input that can edit each item.text?Bert
@BertEvans message comes from child. I want to bind the input to message. I am just curious if it is possible to have each editable item.text and still use scoped slot.David
Do you want one input that edits message per list item or just the one input at the bottom?Bert
@BertEvans One input that edits message per list item. Sorry that original code confused you. I just wanted to show that I am not sure where to put that input field as it only appears at the bottom.David
More like this then? codepen.io/Kradek/pen/RpveGyBert

1 Answers

3
votes

Base on our discussion, I think essentially what you want is this. Because you want the message to be independently editable, it needs to be part of the item. If you make message part of my-list, then all the messages will be the same. After that, all you need to do is pass the item to the scoped template.

Vue.component("my-list",{
  props:["items"],
  template: "#my-list-template",
})

new Vue({
  el:"#app",
  data:{
    items:[
      {text: "item 1", message: "message 1"},
      {text: "item 2", message: "message 2"},
      {text: "item 3", message: "message 3"}
    ]
  }
})

And the templates:

<div id="app">
  {{items}}
  <my-list :items="items"> 
      <template slot="item" scope="props">
        <li class="my-fancy-item">{{ props.item.text }}</li>
        <div> 
             <input v-model="props.item.message"> 
         </div>
         <p>{{props.item.message}}</p>
      </template>
  </my-list>

</div>

<template id="my-list-template">
  <ul>
     <slot name="item" 
           v-for="item in items" 
           :item="item">
    </slot>
  </ul>
</template>

Here is the working example.