vue observable

When making a vuejs project there might end up being situations in which I might want to make an object observable, or reactive. When it comes to making a vue data object such an object is observable to begin with at least when it comes to the top level of the object. However this might not always end up being the case when it comes to nested objects in the data object, and it is also not the case when it comes to an object that is outside of a vuejs instance compleatly.

In some situations I might have to do something to make sure that nested objects in the data object become observable when I add them to the data object. When it comes to those kinds of situations I might want to go with the vue set method. However what if I want to make a plain old object outside of a vuejs instance completely observable? Well one way is the use the vue observable Global API method.

So this will be a quick post on using the vue observable global API method, and in the process of doing so I guess I will end up touching base the the subject of reactivity using vuejs also. There is also taking a moment to get into the vanilla javaScript feature that is used to make reactive objects possible when it comes to understanding getters and setters in plain old javaScript by itself.

1 - Basic vuejs observable example

In this section I will be going over a basic example of the vue observable global API method. This example involves using the vue render option as a way to create and update a vue rather than a simple vue template. If you are not familiar with creating a render method let alone a static template in vuejs then you will want to brush up on that before hand.

So say I have a state object that is just a plain old object outside of a vuejs instance, and it is this object that I am using as a state for the project rater than the vue data object. If I do not make this state object observable then the vue will not just update each time a change is made to the object. However this can easily be fixed by just calling the Vue.observable method and passing the state object as the first argument for this method. Now when I make changes to the state object in one of my methods in the vuejs instance the change to the state object will cause the vue to render again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<html>
<head>
<title>vue observable example</title>
<script src="/js/vuejs/2.6.10/vue.js"></script>
</head>
<body>
<div id="demo"></div>
<script>
var state = Vue.observable({
count: 0
});
new Vue({
el:'#demo',
render : function(createElement){
return createElement('input', {
attrs: {
type: 'button',
value: 'count: ' + state.count
},
on: {
click: this.click
}
});
},
methods: {
click : function(){
state.count += 1;
}
}
});
</script>
</body>
</html>

So then that is the basic idea of the Vue.observable method, it is just a way to go about making any javaScript object observable. When such a task is done changes to that object will update the view in which the object is used. However this might not always be the best way to go about doing things as it strikes me as a kind of temporary duct tape like solution. When it comes to creating a project with vuejs I might have some kind of vanilla javaScript module that will create and update a state object, but often such a module will have a main create method that I can call in a function that I use with the vue data option.

2 - Avoding the use of Vue.observable

I try to do my best to avoid using methods like Vue.observable actually, because it seems like if I code things a certain way it is not needed. If I have an external state object as a single stand alone object, and I do not want to make that object part of a vue instance and keep it in its own separate place then maybe that is how I have to go about doing it. Still I think that an extremal state object should not just be a single state alone object but the result of the calling of a constructor function, or some kind of main create method in a module. This way I can call such a create method inside the body of a function that I use with the data option of the main vue constructor, this seems to work well for me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html>
<head>
<title>vue observable example</title>
<script src="/js/vuejs/2.6.10/vue.js"></script>
</head>
<body>
<div id="demo"></div>
<script>
// A vanilla javaScript State module
var stateMod = (function(){
var api = {};
api.create = function(){
return {
count: 0
};
};
api.update = function(state){
state.count += 1;
};
return api;
}());
// a vuejs instance
new Vue({
el:'#demo',
data: function(){
return {
state: stateMod.create()
};
},
render : function(createElement){
return createElement('input', {
attrs: {
type: 'button',
value: 'count: ' + this.$data.state.count
},
on: {
click: this.click
}
});
},
methods: {
click : function(){
stateMod.update(this.$data.state);
}
}
});
</script>
</body>
</html>

3 - Getters and setters under the hood.

The trick about reactive objects in vuejs is that javaScript getters and setters are used in order to make objects observable. It might be a good idea to take a moment to play around with them a little on their own to get a better sense of how they work.

The Object.definePropery method can be used as a way to create getters and setters for an object property. This native javaScript method is worth looking into if you have not done so all ready because it is not just used to create getters and setters for an object, it can also be used to set objects as enumerable or not for example. In the body of a setter it is possible to not just set what the value of the property should be with some javaScript code, it is also possible to fire some additional methods that should fire each time the object property is set. One of these additional methods can be something that updates a vue for the object for example which is more or less what is going on inside vuejs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<html>
<head>
<title>getter example</title>
</head>
<body>
<div id="demo"></div>
<script>
// a create reactive helper that will use getters and setters
var createReactive = function (obj, onSet) {
obj = obj || {};
onSet = onSet || function () {};
var newObj = {};
Object.defineProperty(newObj, 'locals', {
enumerable: false,
value: {}
});
Object.keys(obj).forEach(function (key) {
Object.defineProperty(newObj, key, {
enumerable: true,
get: function () {
return this.locals[key];
},
set: function (newValue) {
this.locals[key] = newValue;
onSet(newObj);
}
});
newObj[key] = obj[key];
});
return newObj;
};
// a render function
var render = function (obj) {
var el = document.getElementById('demo');
el.innerText = obj.n;
};
var a = createReactive({
n: 42
}, render);
// a chnage to a.n will call the render function
a.n = 15;
</script>
</body>
</html>

What is nice about using something like vuejs is that I can hind all of this kind of stuff away into an external file resource, and I can just focus more on what really matters in a project. I do like to create projects from the ground up with just native javaScript by itself, however doing so is time consuming, and it does not always result in a better final product anyway.

4 - conclusion

So the vue observable method is there for quickly turning a plain old external object into a reactive one. Often the use of the method is not need though at least I can not say I am using the method that often thus far. In most cases I use the vue data object option as a way to create a state for the vuejs instance, and each time that is the case the object becomes observable to begin with. It is only in cases where things are not working as expected with reactivity that the vue observable method might have to be used in order to get that feature of vuejs to work with a project.