msqar
msqar

Reputation: 3040

$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?

Upvotes: 1

Views: 4571

Answers (3)

Brian Lee
Brian Lee

Reputation: 18197

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>

Upvotes: 2

Elvin Bayramov
Elvin Bayramov

Reputation: 107

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>

Upvotes: -1

Bhaskar
Bhaskar

Reputation: 1946

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
}

Upvotes: 1

Related Questions