jabe
jabe

Reputation: 834

Why does one Vue instance update with the data while another view instance doesn't?

I am using Vue for the first time, and am confused about why one of my Vue objects keeps updating when the data changes, and the other Vue object won't.

I have a JavaScript module like this to basically just hold data:

var MyModule = (function(){

    const info = {
        requestCount: 20,
        arrayOfItems: []
    }

    return info;
})();

I have this html:

<span id='requestCounter' class='badge'>{{count}}</span>

<table id='vueTable'><tr v-for="item in items"><td>{{item.description}}</td></tr></table>

And lastly, I have this JavaScript file to do everything:

window.onload = function(){
    var mainTable = new Vue({
        el: '#vueTable',
        data: {
            items: MyModule.arrayOfItems
        }
    });

    var requestCounterVue = new Vue({
        el: '#requestCounter',
        data: {
            count: MyModule.requestCount
        }
    });
}

On the first runthrough, everything works as intended. Changing the MyModule.arrayOfItems works correctly, the table updates depending on what is in the array. However, changing MyModule.requestCount doesn't do anything. Can anybody tell me what I'm doing wrong here?

(Note, my example is simplified to make my question easier)

Upvotes: 1

Views: 426

Answers (2)

Bert
Bert

Reputation: 82459

Roy is exactly right. I'm just leaving this here because I was typing while he answered, and possibly more explanation couldn't hurt.

MyModule doesn't become reactive just because you use it to initialize values in your Vues. I expect the reason arrayOfItems is working the way you expect is because you are not actually setting it to a new array, you are mutating the existing array.

For example, your Vue using the array is defined here.

var mainTable = new Vue({
    el: '#vueTable',
    data: {
        items: MyModule.arrayOfItems
    }
});

If you add a value to MyModule.arrayOfItems like this

MyModule.arrayOfItems.push('my new value')

then your Vue will show the new value. This is because mainTable.items and MyModule.arrayOfItems are pointers to the same array.

If instead, however, you modified MyModule.arrayOfItems like this

MyModule.arrayOfItems = ['my','new','array']

Then mainTable will not show the updated array. This is because you've changed it to a completely different array. In other words, MyModule.arrayOfItems !== mainTable.items.

This is also the reason changing MyModule.count to a new value is not reflected in requestCounterVue. MyModule.count is a primitive value and when you initialized requestCounterVue with count, it used a copy of the value and made the copy reactive. Changing MyModule.count will have no effect.

If you wanted to see the changes reflected, what you might do is initialize your Vues this way

var mainTable = new Vue({
    el: '#vueTable',
    data: MyModule
});

When the Vue is instantiated, MyModule will be turned into a reactive object and changes will be reflected for both count and arrayOfItems.

Upvotes: 2

Roy J
Roy J

Reputation: 43881

You are initializing the data in your Vue objects from MyModule. This does not make MyModule a proper store or controller. The weird behavior is not that requestCount doesn't react, but that arrayOfItems does.

The reason the array behaves as it does is that objects are passed by reference, so when you initialize items, Vue gets hold of the actual array object and does its magic on it. Effectively, MyModule provides an external handle to your Vue data.

requestCount, on the other hand, is a simple value, not an object, so it is passed by value, and there is absolutely no relationship between the member in MyModule and the data item in requestCounterVue.

Upvotes: 2

Related Questions