2

In Vue 2, I'm trying to use a custom event handler that receives arguments from a component and receives the current index (from v-for) as an argument.

I've found several ways to do this (hat-tip to Vue 2 arguments in inline (in-template) event handler), but they all seem to depend on implementation details of Vue. Here's what I'm trying to do (the commented-out HTML also works):

Vue.component('product', {
  template: '<button @click="handleClick">Do Fun Stuff</button>',
  methods: {
    handleClick: function() {
      this.$emit('fun-stuff', 'foo', 'bar');
    }
  }
});

new Vue({
  el: '#app',
  data: {
    callbackData: '',
    items: [1, 2, 3, 4, 5],
    message: 'Hello Vue!'
  },
  methods: {
    handleFunStuff: function() {
      var argString = Array.prototype.join.call(arguments, ' ');
      this.callbackData = this.message + ' - ' + argString;
    }
  }
});
<div id="app">
  <p>{{message}}</p>
  <template v-for="(i, index) in items">
    <product @fun-stuff="function(stuff, things) { handleFunStuff(index, stuff, things) }">
    </product>
    <!--
      <product @fun-stuff="handleFunStuff(index, arguments[0], arguments[1])">
      </product>
      -->
    <!--
      <product @fun-stuff="handleFunStuff.bind(null, index).apply(null, arguments)">
      </product>
      -->
  </template>
  <p>{{callbackData}}</p>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>

Is there a more proper way to do this in Vue?

Coming from Angular 1, this is possible (since component callback arguments are named) and (in my experience) used commonly.

3
  • I think your approach is fine, and is the Vue way to do this. Commented Jan 24, 2017 at 2:58
  • @CodinCat I had a couple approaches in there. Do you mean the function(stuff, things) { handleFunStuff(index, stuff, things) } or handleFunStuff(index, arguments[0], arguments[1]) approach? Commented Jan 24, 2017 at 15:22
  • Oh I meant the highlighted one, it's easier to read, and the child doesn't need to be aware of the index Commented Jan 25, 2017 at 3:29

2 Answers 2

1

Another option is to use the special $event argument.

Here's a Codesandbox showing it in action.

Sign up to request clarification or add additional context in comments.

Comments

1

You should pass index as a prop to the component.

Vue.component('product', {
  template: '<button @click="handleClick">Do Fun Stuff</button>',
  props: ['idx'],
  methods: {
    handleClick: function () {
      this.$emit('fun-stuff', this.idx, 'foo', 'bar');
    }
  }
});

new Vue({
  el: '#app',
  data: {
    callbackData: '',
    items: [1, 2, 3, 4, 5],
    message: 'Hello Vue!'
  },
  methods: {
    handleFunStuff: function() {
      var argString = Array.from(arguments).join(' ');
      this.callbackData = this.message + ' - ' + argString;
    }
  }
});
<div id="app">
  <p>{{message}}</p>
  <template v-for="(i, index) in items">
    <product :idx=index @fun-stuff="handleFunStuff">
    </product>
  </template>
  <p>{{callbackData}}</p>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>

2 Comments

Whoops, should've mentioned that in my question. I knew that was an option, but I was hoping to avoid it. It seems like the index is outside the component's area of concern? I suspect this answer is the "correct" one though.
The fact that it's an index is outside the component's area of concern, but you want the component to be individually identifiable, so you have to provide it with an identifier.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.