-
Star
(828)
You must be signed in to star a gist -
Fork
(195)
You must be signed in to fork a gist
-
-
Save eligrey/384583 to your computer and use it in GitHub Desktop.
| /* | |
| * object.watch polyfill | |
| * | |
| * 2012-04-03 | |
| * | |
| * By Eli Grey, http://eligrey.com | |
| * Public Domain. | |
| * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | |
| */ | |
| // object.watch | |
| if (!Object.prototype.watch) { | |
| Object.defineProperty(Object.prototype, "watch", { | |
| enumerable: false | |
| , configurable: true | |
| , writable: false | |
| , value: 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 | |
| Object.defineProperty(this, prop, { | |
| get: getter | |
| , set: setter | |
| , enumerable: true | |
| , configurable: true | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| // object.unwatch | |
| if (!Object.prototype.unwatch) { | |
| Object.defineProperty(Object.prototype, "unwatch", { | |
| enumerable: false | |
| , configurable: true | |
| , writable: false | |
| , value: function (prop) { | |
| var val = this[prop]; | |
| delete this[prop]; // remove accessors | |
| this[prop] = val; | |
| } | |
| }); | |
| } |
I wanted to add a few keywords for people searching for this type of solution, I am using this with Node.JS / Express.JS and it works perfectly!
Thanks
simple delete prop make it looks like not so perfect, if somewhere have call Object.defineProperty(target, targetProto) before watch , so the setter and getter (if exist) can't work
take a look at my modification, sorry for that i have not test it yet
https://gist.github.com/xsilen/e301dd675d27f3fa036a
and also sorry for unwatch implement
Excellent!
Thanks for this one.
Seems there's an issue undefined on the oldval
var myObject = {test:"a"};
myObject .watch("test", function (id, oldval, newval) {
console.log(oldval+' '+ newval);
});
myObject .test = "b"; // "a b"
myObject .test = "c"; // "undefined c"
@rokobuljan That's not an issue... You're not returning the desired new value in the watch.
var myObject = {test:"a"};
myObject .watch("test", function (id, oldval, newval) {
console.log(oldval+' '+ newval);
return newval;
});
myObject .test = "b"; // "a b"
myObject .test = "c"; // "b c"
Hey man! I made an awesome popup blocker with your snippet. https://gist.github.com/MMDF/d793c6dced90a41495a1dd61d6bf2f5b
Take a look and add it to Tampermonkey to use it. Thanks for the public snippet!
This was a day saver. Thanks for your nice snippet :)
A more generic version is possible. Instead of getting directly this[prop] at the start, the watch function should try to getOwnPropertyDescriptor on the object or along its prototype chain until it succeeds, then handle accessor properties by invoking the original getter/setter. This way you can watch html input elements "value" and "checked" properties for programmatic modification for example.
Has anyone developed a version that would track children properties too?
@mateuszgwozdz Vue.js can do it.
@georgir What are you referring to, exactly? Can you provide an example?
Is it possible to watch window and check when variable is set with var el?
value: function( prop, handler ){
var oldval = this[prop],
getter = () => ( oldval ),
setter = function( val ){
if ( oldval != val ){ // event with a different value
handler.call( this, prop, oldval, val);
return ( oldval = val );
}
};
@stefek99 : the handler function must return the new value
alternatively, if you want a behavior more akin watchers in vue/react/angular you can modify the setter function as follows:
setter = function (val) {
oldval = newval;
return newval = (function() {
handler.call(this, prop, oldval, val);
return val;
})();
};
if forces the new value to always be passed and assigned to the property, and the handler function becomes just "notified" of the change
I can't get this working with DOM Elements. e.g. https://gist.github.com/robianmcd/ee9a5f10dca11e357c9c
Am I doing something wrong?