2

I have a Vue component that has an $emit event. I'd like to have a method that receives the callback (with data from the $emit), but also accepts another parameter. I would think that having a method return a function would accomplish this, but I can't seem to get it working.

<my-component @callback="notifyCallback" />

I can easily receive the data from the $emit like this:

methods: {
  notifyCallback(data) {
    console.log(data)
  }
}

But I would like to use the same callback method for multiple $emit events with different names, while still receiving the data sent from the $emit. My thinking is that having the method return a function would do the trick. Something like this:

<my-component 
  @callback-a="notifyCallback('callback-a')"
  @callback-b="notifyCallback('callback-b')"
/>

methods: {
  notifyCallback(callbackKey) {
    return function(data) {
      console.log(`Callback: ${callbackKey} has data: ${data}`)
    }
  }
}

But this approach of having the method return a function doesn't seem to work.

Am I thinking about this incorrectly? Is there a way to accomplish having a method return a function?

Or, more directly at my desired goal ... is there a way to have a callback method receive an extra parameter along with the data in the $emit?

Thanks so much for your input!

Note: I realize I could pass the callbackKey with the $emit data, but the approach of having a method return a function seems like it should work, so I'm mostly curious about why it isn't, and what I'm misunderstanding.

1 Answer 1

3

The v-on directive takes either a method name or an inline handler. The inline handler's return value is unused, and returning a function would not setup a new event handler. Your inline handler generates a function with notifyCallback() and does nothing with it.

Note that the inline handler has a special variable ($event) that contains the event data from $emit().

A small tweak to your original code could accomplish your goal, but it seems suboptimal for your use case, as it unnecessarily creates the same callback on every event:

<my-component 
  @callback-a="notifyCallback('callback-a')($event)"
  @callback-b="notifyCallback('callback-b')($event)"
/>

Vue.component('my-component', {
  template: `<div>
      <button @click="emitData('callback-a')">Event A</button>
      <button @click="emitData('callback-b')">Event B</button>
    </div>`,
  methods: {
    emitData(eventName) {
      this.$emit(eventName, {
        foo: `${eventName} 1`,
        bar: `${eventName} 2`,
      })
    }
  }  
});

new Vue({
  el: '#app',
  methods: {
    notifyCallback(callbackKey) {
      return function(data) {
        console.log(`Callback: ${callbackKey} has data: ${JSON.stringify(data)}`)
      }
    }
  }
})
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <my-component 
    @callback-a="notifyCallback('callback-a')($event)"
    @callback-b="notifyCallback('callback-b')($event)"
  />
</div>

A cleaner solution might be to handle the event directly in notifyCallback():

<my-component 
  @callback-a="notifyCallback('callback-a', $event)"
  @callback-b="notifyCallback('callback-b', $event)"
/>

methods: {
  notifyCallback(callbackKey, data) {
    console.log(`Callback: ${callbackKey} has data: ${data}`)
  }
}

Vue.component('my-component', {
  template: `<div>
      <button @click="emitData('callback-a')">Event A</button>
      <button @click="emitData('callback-b')">Event B</button>
    </div>`,
  methods: {
    emitData(eventName) {
      this.$emit(eventName, {
        foo: `${eventName} 1`,
        bar: `${eventName} 2`,
      })
    }
  }  
});

new Vue({
  el: '#app',
  methods: {
    notifyCallback(callbackKey, data) {
      console.log(`Callback: ${callbackKey} has data: ${JSON.stringify(data)}`)
    }
  }
})
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <my-component 
    @callback-a="notifyCallback('callback-a', $event)"
    @callback-b="notifyCallback('callback-b', $event)"
  />
</div>

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

Comments

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.