Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Vuejs is not updating model until input loses focus

Tags:

vue.js

vuejs2

My app works with the following kind of data: There are companies which each have a list of datapoints. Each datapoint has a single type and each company can only have one datapoint of each type.

+Company_1  
|  
|--Datapoint_1 : type_1  
|--Datapoint_2 : type_2  
|--Datapoint_3 : type_3  
|  
|  
+Company_2  
|  
|--Datapoint_4 : type_3  
|--Datapoint_5 : type_2  
|  
|+Company_3  
|  
|--Datapoint_6 : type_2  
...  
...  

In total there are about 1000 datapoints and 20 companies. The app calculates analytics based on these datapoints and the goal is to allow users to manipulate these datapoints in order to see what the results would look like in a given scenario. At any given moment, there is a "selected_company" and "selected_type" and based on these two selections, the correct datapoint should be chosen for manipulation.

I realised that if the "companies" variable, and "datapoints" property were arrays, a search would have to be done on all the items in order to find the correct ones. I therefore chose to make them objects :

companies = {
  '1' : {
    name : 'Company_1',
    datapoints : {
      'type_1' : { ... },
      'type_2' : { ... },
      'type_3' : { ... }
    }
  },
  '2' : {...},
  '3' : {...},
  .
  .
  .
}

Problem:

I have a 'datapoint' component, that I am passing datapoints as props :

<datum-comp :datum="companies[selected_company].datapoints[selected_type]"></datum-comp>

Within this component, I have an input that is used to manipulate the score property of the datapoint:

<input v-model.number="datum.score" class="form-control">

However, this input is exhibiting very strange behaviour. As I type into the input, the model is not immediately updated. Instead, Vue seems to be waiting for me to change focus from the input (onBlur) before updating the model.

not updating until onblur

Even more weird, is that when I make the datapoints property an array

companies = {
      '1' : {
        name : 'Company_1',
        datapoints : [
          { ... },
          { ... },
          { ... }
        ]
      },

and use a method to retrieve the datapoint (as opposed to directly passing it in), Vue functions the correct way!

<datum-comp :datum="getDatum(selected_company, selected_type)"></datum-comp>

(in js file:)

var app = new Vue({
    el : '#app',
    data:{...},
    methods:{
      getDatum: function(selected_company, selected_type){
          var datum = this.companies[selected_company].datapoints.find(function(elem){
            return elem.type == selected_type
          })
          return datun
        }
    }
  })

updating correctly

I need help understanding why Vue behaves like this under these circumstances as it has some serious implications for app performance. Thanks in advance.

like image 615
Vasco Avatar asked Feb 18 '18 18:02

Vasco


1 Answers

v-model is just syntax sugar for...
:value="modelValue" @input="modelValue = $event.target.value"
As you say, it updates the model oninput, which works well most of the time.

If you want something else, it's very easy to do. Just change the update side to onkeypress, so...

<input  class="form-control
    :value="datum.score" 
    @keypress="datum.score = $event.target.value""
    @input="datum.score = $event.target.value""
>

The changes you're noticing when you change datapoints from an array to an object are likely due to the fact that Vue cannot detect changes made in an array using array syntax (square brackets). You need to use array methods (push, pop, splice, etc.) or Vue.set(). Like you say, this is not intuitive, but it's one of the very few traps in Vue. It's due to limitations of javascript, and it's well covered in the doc.

like image 85
bbsimonbb Avatar answered Nov 15 '22 06:11

bbsimonbb