Vue: In 2.5.1+, v-model cannot be combined with v-on="$listeners"

Created on 10 Nov 2017  路  4Comments  路  Source: vuejs/vue

Version

2.5.1+

Reproduction link

https://jsfiddle.net/bvyo2yra/

Steps to reproduce

See the minimal reproduction.

What is expected?

Previous to 2.5.1, v-on="$listeners" could be used in combination with more specific event handlers to create components that could transparently pass events to an element inside them. This worked because the more specific listeners (e.g. @input="$emit('input', $event.target.value)) were called _after_ the more generic listeners with v-on="$listeners.

What is actually happening?

In 2.5.1, these higher priority listeners are now triggered first, so that if the listener sets a value, it will set the correct value, _then_ the incorrect value, breaking v-model.


The breaking change was made to solve another issue, so it's probably not ideal to just revert the change. And actually, even the previous behavior was slightly undesirable, as it emitted the same event twice.

To fix both issues, I would actually expect the more specific event binding (e.g. @input) to _replace_ the listener of the same name from v-on with the object syntax. The more specific listener would then take responsibility for emitting an event at the correct time. That allows the user full, explicit control over the order in which local handlers and handlers from the parent are called.

How does that sound to others?

discussion nextTick related

Most helpful comment

Yeah, I'm not a fan of the workaround - it feels a bit hacky. What would you think about suggesting the following pattern instead?

<input 
  :value="value" 
  v-on="{
    ...$listeners,
    input: event => $emit('input', event.target.value)
  }"
>

All 4 comments

The replacing behavior would also be a breaking change though. I think preserving both is more semantically correct, and among the two, the current behavior in 2.5.1+ is the more reasonable (disregarding combined usage with v-model).

I think the goal really should be how can we make v-model and v-on="$listeners" work together while retaining the semantically correct behavior. There is currently a workaround I mentioned here, although it's not very straightforward and requires understanding of the internals.

Yeah, I'm not a fan of the workaround - it feels a bit hacky. What would you think about suggesting the following pattern instead?

<input 
  :value="value" 
  v-on="{
    ...$listeners,
    input: event => $emit('input', event.target.value)
  }"
>

@chrisvfritz that's actually reasonable. It's explicitly overwriting the parent input listener.

Excellent. I've updated the docs and this issue can probably be closed, but I agree that long-term, it really would be nice for v-model listeners just automatically work.

Ideally, v-model listeners on components could:

  1. Check if the emitted payload is an Event...

    • If yes, check event.target.tagName to choose the appropriate element listener

    • If no, use the normal behavior for v-model on components, where the payload is assumed to be the new value

Was this page helpful?
0 / 5 - 0 ratings