Watch for Object Properties Changes in JavaScript

Listener for property value changes in a Javascript object

What watch is really designed for is validation of property values. For example you could validate that something is an integer:

obj.watch('count', function(id, oldval, newval) {
var val = parseInt(newval, 10);
if(isNaN(val)) return oldval;
return val;
});

You could use it to validate string length:

obj.watch('name', function(id, oldval, newval) {
return newval.substr(0, 20);
});

However, these are only available in the latest versions of the SpiderMonkey javascript engine. Great if you are using Jaxer or embedding the SpiderMonkey engine, but not really available in your browser yet (unless you are using FF3).

How to watch complex objects and their changes in JavaScript?

As @Booster2ooo mention you can use Proxy object to observe the changes, you can use something like this:

function proxify(object, change) {
// we use unique field to determine if object is proxy
// we can't test this otherwise because typeof and
// instanceof is used on original object
if (object && object.__proxy__) {
return object;
}
var proxy = new Proxy(object, {
get: function(object, name) {
if (name == '__proxy__') {
return true;
}
return object[name];
},
set: function(object, name, value) {
var old = object[name];
if (value && typeof value == 'object') {
// new object need to be proxified as well
value = proxify(value, change);
}
object[name] = value;
change(object, name, old, value);
}
});
for (var prop in object) {
if (object.hasOwnProperty(prop) && object[prop] &&
typeof object[prop] == 'object') {
// proxify all child objects
object[prop] = proxify(object[prop], change);
}
}
return proxy;
}

and you can use this fuction like this:

object = proxify(object, function(object, property, oldValue, newValue) {
console.log('property ' + property + ' changed from ' + oldValue +
' to ' + newValue);
});

...

Watch for object properties changes in JavaScript

I have created a small object.watch shim for this a while ago. It works in IE8, Safari, Chrome, Firefox, Opera, etc.

/*
* object.watch v0.0.1: Cross-browser object.watch
*
* By Elijah Grey, http://eligrey.com
*
* A shim that partially implements object.watch and object.unwatch
* in browsers that have accessor support.
*
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/

// object.watch
if (!Object.prototype.watch)
Object.prototype.watch = function (prop, handler) {
var oldval = this[prop], newval = oldval,
getter = function () {
return newval;
},
setter = function (val) {
oldval = newval;
return newval = handler.call(this, prop, oldval, val);
};
if (delete this[prop]) { // can't watch constants
if (Object.defineProperty) // ECMAScript 5
Object.defineProperty(this, prop, {
get: getter,
set: setter
});
else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { // legacy
Object.prototype.__defineGetter__.call(this, prop, getter);
Object.prototype.__defineSetter__.call(this, prop, setter);
}
}
};

// object.unwatch
if (!Object.prototype.unwatch)
Object.prototype.unwatch = function (prop) {
var val = this[prop];
delete this[prop]; // remove accessors
this[prop] = val;
};

Vue.js - How to properly watch for nested data

You can use a deep watcher for that:

watch: {
item: {
handler(val){
// do stuff
},
deep: true
}
}

This will now detect any changes to the objects in the item array and additions to the array itself (when used with Vue.set). Here's a JSFiddle: http://jsfiddle.net/je2rw3rs/

EDIT

If you don't want to watch for every change on the top level object, and just want a less awkward syntax for watching nested objects directly, you can simply watch a computed instead:

var vm = new Vue({
el: '#app',
computed: {
foo() {
return this.item.foo;
}
},
watch: {
foo() {
console.log('Foo Changed!');
}
},
data: {
item: {
foo: 'foo'
}
}
})

Here's the JSFiddle: http://jsfiddle.net/oa07r5fw/

How to subscribe to object changes?

Have you tried using Proxy from ECMA6? I think this is what you are looking for
You only have to define a function as the set of the validator of the Proxy like this:

let validator = {
set: function(target, key, value) {
console.log(`The property ${key} has been updated with ${value}`);
return true;
}
};
let store = new Proxy({}, validator);
store.a = 'hello';
// console => The property a has been updated with hello

ECMAscript 6: watch changes to class properties

There's no 'best' way, and the actual approach always depends on the final goal.

In its simplistic (and performant enough) form it is:

class MyClass {

constructor (a) {
this.a = a;
}

get a() {
return this._a;
}

set a(val) {
this._a = val;
this._onPropertyChanged('a', val);
}

_onPropertyChanged(propName, val) {
// do something
}
}

Watch on all attributes of an object in AngularJS

Use the third argument of $watch, like this :

$scope.$watch('content', function(){
// do some work
}, true);

If this is true, the expression is evaluated for object equality, which means properties are included. Otherwise it's just evaluated for reference.



Related Topics



Leave a reply



Submit