question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Should v-model work on components using both v-bind="$attrs" and v-on="$listeners"?

See original GitHub issue

What problem does this feature solve?

Following this discussion, given a CustomInput component with this template:

<div>
  <input v-bind="$attrs" v-on="$listeners">
<div>

The following currently does not work:

<CustomInput v-model="myValue" />

The problem is that v-model on a component expects a value on input events, but a DOM Event is passed to the listener instead.

What does the proposed API look like?

Option 1: Make v-model smarter

Since I think it’s unlikely that anyone will want to use v-model with a DOM Event, perhaps when v-model is used on components, it could check if the argument passed to the listener is instanceof window.Event. Then if it is, use event.target.value instead.

Option 2: Make v-on smarter

Maybe a non-enumerable property could be added to $listeners (e.g. __$listeners__: true, to help v-on detect uses of v-on="$listeners". Then in cases where the $listeners object is passed to v-on and it’s used on an element, listeners relevant to v-model could be wrapped:

function (event) {
  listener(event.target.value)
}

But now we’re throwing away data. If someone wants to access a keyCode - e.g. with @input instead of v-model - they’re out of luck. However, if modifiers were also supported for v-on’s object syntax, we could fix this by making .native disable the automatic wrapping behavior.


Thoughts? Are there strategies or implications I’m not considering? I’m definitely open to alternatives.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:16
  • Comments:19 (12 by maintainers)

github_iconTop GitHub Comments

3reactions
Hamido-sancommented, Aug 8, 2020

All we want is to be able to create “fully transparent wrapper” components and add some functionality/customization on top… to have some semblance of inheritance in Vue. Why all these edge cases and special syntax just for that? Why is it not the default behavior already?

3reactions
yyx990803commented, Oct 2, 2017

So, I finally gave this proposal a proper investigation, and it ends up being more complicated than it seems. The problem lies within consistency between different input types. The current implementation in #6327 assumes a text input and ignores non-input events. While this simplifies wrapping plain text input fields, it makes the whole thing inconsistent and feels like a special-case convenience hack.

I managed to make it work with <input type="checkbox">, which requires the component to specify the model option, and then injecting the event type and prop type back into the component v-model handler. It’s already messier than I hoped - but even if this works, it becomes prohibitively complex to mimic the full behavior of native v-model (e.g. checkboxes with array binding, radio, select…)

At this point I feel the implementation cost and the inconsistency outweighs the simplification this change would bring.

Taking a step back, the whole idea of component v-model is opening up finer-grained control over the two-way binding of form inputs, not simplifying it. Its job is expanding the sugar consistently into a pair of input and output, and letting you fill in the details. Mixing that up with $attrs and $listeners feels like magic where it doesn’t belong.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using v-model + $attrs on Vue Components | by Filip Stępień
The v-model directive is used to create a two-way data binding in Vue by doing two things: It binds a value attribute to...
Read more >
vue.js - v-model and child components?
When a component doesn't have any declared props, this essentially contains all parent-scope bindings (except for class and style ), and can be ......
Read more >
Making sense of Multiple v-model Bindings in Vue 3
In Vue 2, to build a complex Component that supports two-way data binding, it utilizes a single v-model with one full-blown payload.
Read more >
What you should know about Vue v-model
Vue v-model is a directive that creates a two-way data binding between a value in our template and a value in our data...
Read more >
VueJS - Different ways to implement v-model
Another way of implementing v-model in your custom component is using computed properties getters and setters. You can define a local computed ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found