Search code examples
javascriptvue.jsvue-reactivity

vue.js element selected by focus is not reactive


I have a listener to check what input was selected at last to add some kind of string/variable later into it.

created: function () {
    document.addEventListener('focusin', this.focusChanged);
}

focusChanged(event) {
    if (event.target.id !== 'variable-search') {
        this.lastElement = event.target;
    }
}

This seems to work fine, and when I click on an input field this.lastElement gets updated with the focused element. All these inputs have a v-model which can be a string in an object or just a plain string.

Now the thing is when I try to update the value by:

this.lastElement.value += variable;

Vue won't detect its changes, also in the Vue Developer tools the string won't get updated. But in the input field it does get updated. So this should be a reactivity thing.

When I add a new character into the input field (v-model) it does update again. So it's just when I update the string by this.lastElement it won't register its changes.

The thing is that the input fields are dynamic, so I don't know how many input fields are here and how many lists etc. So I need Vue to re-render the variable after the value of lastElement is updated.

Edit

I just tried it with an @focus here an example

<input v-model="testVar" @focus="lastElement = testVar">

If I update lastElement later on it doesn't update it for testVar but just for lastElement.


Solution

  • Changing values in DOM elements programmatically does not cause DOM events to fire. v-model relies on input (or change when using .lazy) events to update its bound variable. If you dispatch those events when you update the value in an input, the variable will react.

    new Vue({
      el: '#app',
      data: {
        items: ['one','two','three']
      },
      methods: {
        addAddress() {
          this.lastElement.value += 'address';
          this.lastElement.dispatchEvent(new Event('input'));
          this.lastElement.dispatchEvent(new Event('change'));
        },
        focusChanged(event) {
          this.lastElement = event.target;
        }
      }
    })
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="app">
      <div v-for="item, index in items">
        <input v-model="items[index]" @focus="focusChanged">
        {{item}}
      </div>
      <button type="button" @click="addAddress">+address</button>
    </div>