Vue: Two way binding on inputs doesn't update input's value directly

Created on 25 Sep 2017  路  7Comments  路  Source: vuejs/vue

Version

2.4.4

Reproduction link

https://jsfiddle.net/vxeyr99x/

Steps to reproduce

  1. Write bbc
  2. Add an 'a' at the end of the input
  3. Add any character that is not 'a' at the end of the input

What is expected?

At step 2, we expect the input value (value of DOM node, the one we see) not to change

What is actually happening?

At step 1, everything works fine.
At step 2 this.input has the correct value but the DOM value is wong
At step 3 the 'a' disappears from the DOM value and everything is back to normal


I don't know if this is by design but this is a strange behavior and I think it would be better if the value of the DOM node was always equal to the :value attribute.

Most helpful comment

This is because the value of input doesn't change, so Vue doesn't update the DOM.
https://jsfiddle.net/j0vLhpdn/

All 7 comments

This is because the value of input doesn't change, so Vue doesn't update the DOM.
https://jsfiddle.net/j0vLhpdn/

This works, but it feels like cracking a nut with sledgehammer. :/ I guess for now I'll only force update the input via a ref.

Maybe vue shoud update $el.value every time the input event is triggered. This way, even if the binded value doesn't change, the node's value will be up to date.

Actually what I described in my previous message wouldn't work if the value filter wasn't done directly by the parent component of the <input>. Which is my case.

Even a $forceUpdate doesn't work as it doesn't force children to re-render.

I have the following tree:

<parent-component>
  <autocomplete-component>
    <input-component>
      <input />
    </input-component>
  </autocomplete-component>
</parent-component>

parent-component is the one filtering the value and passing it down the component tree. How can I force <input /> to re-render?

Since this has turned into a question/discussion, please move it to the forum or chat room instead.

I would still consider this a (small) bug as the :value attribute and the node's actual value are unsynched until :value actually changes.

And their is currently no quick workaround as $forceUpdate only re-renders the current component and not its children.

I'll post here if I find a workaround that others can use.

I would suggest to use http://nosir.github.io/cleave.js/

Thanks for the suggestion but the problem is that I would have to bind Cleave to the <input/> itself, I wouldn't be able to in it to parent components using the input.

So the (dirty) solution I've found is the following. With the following component tree:

<parent-component>
  <autocomplete-component>
    <input-component>
      <input />
    </input-component>
  </autocomplete-component>
</parent-component>

The parent-component adds a ref="input" attribute on <autocomplete>. This way, when the input event is triggered, I force the node's value to update with: this.$refs.input.$el.querySelector('input').value = this.input; where this.input is my sanitized value.

This is hacky works in my case as there will be only 1 input element in the <autocomplete> component and I don't need to support browsers that doesn't support documentSelector.

Was this page helpful?
0 / 5 - 0 ratings