Skip to content

Instantly share code, notes, and snippets.

@kevincennis
Last active May 18, 2018 14:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevincennis/25ba31b2e9f9c8b7a34047ba0108aff0 to your computer and use it in GitHub Desktop.
Save kevincennis/25ba31b2e9f9c8b7a34047ba0108aff0 to your computer and use it in GitHub Desktop.
ProxyModel.js
'use strict';
const Model = ( () => {
// event cache
const events = new WeakMap();
// proxy handler
const handler = {
set( target, key, value, receiver ) {
if ( target.validators && target.validators[ key ] ) {
if ( !target.validators[ key ]( value ) ) {
throw new TypeError(`value ${ value } for key ${ key } is invalid`);
}
}
receiver.emit( 'change', key, value );
return target[ key ] = value;
}
};
// Model class
class Model {
constructor( opts ) {
const proxy = new Proxy( this, handler );
Object.assign( this, opts );
events.set( proxy, Object.create( null ) );
return proxy;
}
on( evt, fn ) {
const cache = events.get( this );
const evts = cache[ evt ] || ( cache[ evt ] = [] );
evts.push( fn );
return this;
}
emit( evt, ...args ) {
const cache = events.get( this );
if ( cache[ evt ] ) {
cache[ evt ].forEach( fn => fn.call( this, ...args ) );
}
return this;
}
off( evt, fn ) {
if ( arguments.length === 0 ) {
events.set( this, {} );
return this;
}
if ( arguments.length === 1 ) {
delete events.get( this )[ evt ];
return this;
}
const cache = events.get( this );
const evts = cache[ evt ];
if ( evts ) {
cache[ evt ] = evts.filter( f => f !== fn );
}
return this;
}
}
return Model;
})();
// usage...
let model = new Model({
validators: {
baz: value => value === 'bing'
}
});
model.on( 'change', ( key, value ) => console.log( `change ${ key }: ${ value }` ) );
model.baz = 'bing'; // works, emits a change event
model.baz = 'boop'; // fails validation, throws a TypeError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment