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
Array.Prototype.Includes VS. Array.Prototype.Indexof
What Is the Meaning of an Underscore in JavaScript Function Parameter
Wrapping a Set of Dom Elements Using JavaScript
JavaScript While Loop Return Value
Replace a String in a File with Nodejs
Converting JSON Results to a Date
Can't Access Cookies from Document.Cookie in Js, But Browser Shows Cookies Exist
Use Jquery to Scroll to the Bottom of a Div with Lots of Text
Angularjs: How to Run Additional Code After Angularjs Has Rendered a Template
JavaScript Custom Event Listener
Getting Image Dimensions Using JavaScript File API
Date Parsing in JavaScript Is Different Between Safari and Chrome
!Function(){ }() VS (Function(){ })()
Dynamic Extension Context Menu That Depends on Selected Text