简体   繁体   中英

$emit event from children to parent item that is inside a v-for in VueJS

let's say I got the following structure:

// parent template
<div v-for="item in items">
   <span>Parent</span>
   <children1>
      // inside children1, i got another children
      <children2 @on:finished="onFinished"></children2>
      <button>Click me</button>
   </children1>
</div>

Then in the children1 methods i would have something like this to listen children2:

methods: {
    onFinished: function () {
       // Here i would like to disable `click me` button and change its text for this particular item inside the iteration
    }
}

From children2 I just execute this when something finishes in there.

this.$emit('on:finished', true)

As I write in the inside of the method, I would like to be able to change with VueJS only one of the items by the $emit from its children. But I was thinking using a data property, but that would affect the entire template, what about using computed maybe? will that work? but how?

Any suggestions?

It seems you're missing the data prop to track the disabled state of each child component. See if this example is what you're looking for, clicking the finish button for each child will disable the other button:

 Vue.component('child-component', { props: ['disabled', 'text'], template: `<div><button :disabled="disabled">{{ text }}</button><button @click="$emit('finished')">Finish</button></div>` }) new Vue({ el: '#app', data () { return { children: [] } }, mounted () { this.children = Array.from(Array(10), (x,i) => { return { id: i, disabled: false, text: 'Click Me' } }) }, methods: { onFinished (e, i) { this.children[i].disabled = !this.children[i].disabled this.children[i].text = this.children[i].disabled ? 'Disabled' : 'Click Me' } } }) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <span>Parent</span> <child-component :disabled="child.disabled" :text="child.text" v-for="(child, i) in children" @finished="onFinished($event, i)" :key="child.id"></child-component> </div> 

First of all, you need to properly listen to the child's emit by

  <div v-for="(item,index) in items">
   <span>Parent</span>
   <children :myIndex='index' @finished="onFinished"></children>
   <button>Click me</button>
  </div>

Notice I have also added an index to your child, which has to be accepted as a prop in your child component

props:[myIndex]

Where onFinished() is a method inside your parent component.

In your child component, emit like this

this.$emit('finished', {state: true, index: myIndex})

Now, you can use this index inside your method-

onFinished(itemState){
this.items[itemState.index].state = itemState.state
}

You can use index of item for changing his state.

    data: function () {
     items: [
       {
          enabled: true  
       },
       {
          enabled: true
        }
    ]

For disabling function:

disableItem (index) {
  this.items[index].enabled = false
}

And in template:

<div v-for="(item, index) in items">
<span>Parent</span>
<children @on:finished="disable(index)"></children>
<button>Click me</button>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM