watchable
The module implements 2 functions: watch()
and unwatch()
to create
and remove watchable fields in an existing object.
These functions can be used through a base-class Watchable()
, a mixin, or as static functions of the base-class. The use of the static functions of the base-class is expected to be the most commen.
The base-class Watchable()
is written as an ES5 class, but can also be used as an ES6 base-class.
Usage
The call Watchable.watch(obj, prop, set_handler, get_handler)
to create
the watch has the following parameters:
-
obj
- the object on which to create the watch -
prop
- the name of the watched field
If the fieldprop
already exists on the objectobj
, its value is kept. -
set_handler
- a function taking 3 parameters:- the name of the property
- the current value, and
- the intended next value.
This handler must return the next value, which may be different from the intended next value, but typically isn't.
-
get_handler
- an optional function taking 2 parameters:- the name of the property, and
- the current value.
This handler must return a value that is returned to the caller, which may be different from the current/actual value, but typically isn't.
The call Watchable.unwatch(obj, prop)
to remove the watch only takes the first 2 parameters: obj
and prop
.
NOTE: when the object, on which the watch is defined, also supports an event-emitter or publish/subscribe protocol, simple, but very powerful, handler functions can be created. This is not shown in the examples.
Static Example
import * as Watchable from 'watchable';
let obj = { a: 1, b: 2, c: 3};
Watchable.watch(obj, 'b', (prop, old, val) => {
console.log(prop+':', old, '=>', val);
return val;
});
obj.b = 5;
// Expect output:
// b: 2 => 5
Using the get_handler is rare, and is probably only useful to debug, unknown or unexpected access to a field.
Watchable.watch(obj, 'c',
(prop, old, val) => {
console.log(prop+':', old, '=>', val);
return val;
},
(prop, val) => {
// optional log
console.log('access property:', prop, ', value:', val);
// optional breakpoint
return val;
},
);
obj.c += 4
// Expect output:
// access property: c, value: 4
// c: 3 => 7
Mixin Example
/**
* Adds the functions `watch()` and `unwatch()` to the prototype
* of the function `cls()`.
* @param {function} cls
*/
function mixinWatchable(cls) {
Object.defineProperties(cls.prototype, {
watch: {
enumerable: false,
configurable: true,
writable: false,
value: function (...args) {return Watchable.watch(this, ...args)},
},
unwatch: {
enumerable: false,
configurable: true,
writable: false,
value: function (...args) {return Watchable.unwatch(this, ...args)},
},
});
}
function Target() {
this.a = 1;
this.b = 2;
this.c = 3;
}
mixinWatchable(Target);
obj = new Target();
obj.watch('a', (prop, old, val) => {
console.log(prop+':', old, '=>', val);
return val;
});
obj.a = 7;
// Expect output:
// a: 1 => 7
Credits and Changes
The original code was written by Eli Grey, in april 2012, as an Object.watch()
polyfill.
The changes made to the original code are:
- the polyfill was changed to the base-class
Watchable()
, - the static functions were added, and
- and the
get_handler
parameter was added to thewatch()
function.