Socket
Socket
Sign inDemoInstall

mobservable

Package Overview
Dependencies
Maintainers
1
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mobservable - npm Package Compare versions

Comparing version 0.4.3 to 0.5.0

logo.svg

40

dist/mobservable.js

@@ -31,2 +31,7 @@ /**

};
mobservable.mobservableStatic.expr = function (expr, scope) {
if (DNode.trackingStack.length === 0)
throw new Error("mobservable.expr can only be used inside a computed observable. Probably mobservable.computed should be used instead of .expr");
return new ComputedObservable(expr, scope).get();
};
mobservable.mobservableStatic.array = function array(values) {

@@ -68,4 +73,4 @@ return new ObservableArray(values);

descriptor.get = function () {
mobservable.mobservableStatic.props(this, key, baseValue);
return this[key];
var observable = this.key = mobservable.mobservableStatic.computed(baseValue, this);
return observable;
};

@@ -776,3 +781,6 @@ descriptor.set = function () {

var _a = mobservable.mobservableStatic.watch(function () { return baseRender.call(_this); }, function () {
_this.forceUpdate();
if (_this.isMounted())
_this.forceUpdate();
else if (mobservable.mobservableStatic.debugLevel)
warn("Rendering was triggered for unmounted component. Please check the lifecycle of the components");
}), rendering = _a[0], disposer = _a[1];

@@ -786,4 +794,30 @@ this._watchDisposer = disposer;

this._watchDisposer();
},
shouldComponentUpdate: function (nextProps, nextState) {
if (this.state !== nextState)
return true;
var keys = Object.keys(this.props);
var key;
if (keys.length !== Object.keys(nextProps).length)
return true;
for (var i = keys.length - 1; i >= 0, key = keys[i]; i--)
if (nextProps[key] !== this.props[key])
return true;
return false;
}
};
mobservable.mobservableStatic.ObservingComponent = function (componentClass) {
var baseMount = componentClass.componentWillMount;
var baseUnmount = componentClass.componentWillUnmount;
componentClass.prototype.componentWillMount = function () {
mobservable.mobservableStatic.ObserverMixin.componentWillMount.apply(this, arguments);
return baseMount && baseMount.apply(this, arguments);
};
componentClass.prototype.componentWillUnmount = function () {
mobservable.mobservableStatic.ObserverMixin.componentWillUnmount.apply(this, arguments);
return baseUnmount && baseUnmount.apply(this, arguments);
};
componentClass.prototype.shouldComponentUpdate = mobservable.mobservableStatic.ObserverMixin.shouldComponentUpdate;
return componentClass;
};
function quickDiff(current, base) {

@@ -790,0 +824,0 @@ if (!base.length)

2

dist/mobservable.min.js

@@ -1,1 +0,1 @@

var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},mobservable;!function(a){function b(b,c){return Array.isArray(b)?new l(b):"function"==typeof b?a.mobservableStatic.computed(b,c):a.mobservableStatic.primitive(b)}function c(a,b){if(!b.length)return[a,[]];if(!a.length)return[[],b];for(var c=[],d=[],e=0,f=0,g=a.length,h=!1,i=0,j=0,k=b.length,l=!1,m=!1;!m&&!h;){if(!l){if(g>e&&k>i&&a[e]===b[i]){if(e++,i++,e===g&&i===k)return[c,d];continue}f=e,j=i,l=!0}j+=1,f+=1,j>=k&&(m=!0),f>=g&&(h=!0),h||a[f]!==b[i]?m||b[j]!==a[e]||(d.push.apply(d,b.slice(i,j)),i=j+1,e++,l=!1):(c.push.apply(c,a.slice(e,f)),e=f+1,i++,l=!1)}return c.push.apply(c,a.slice(e)),d.push.apply(d,b.slice(i)),[c,d]}function d(a){console&&console.warn("[WARNING:mobservable] "+a)}function e(a){var b=!1;return function(){return b?void 0:(b=!0,a.apply(this,arguments))}}a.mobservableStatic=function(a,c){return b(a,c)},a.mobservableStatic.value=b,a.mobservableStatic.primitive=a.mobservableStatic.reference=function(a){return new g(a).createGetterSetter()},a.mobservableStatic.computed=function(a,b){return new h(a,b).createGetterSetter()},a.mobservableStatic.array=function(a){return new l(a)},a.mobservableStatic.props=function o(b,o,c){switch(arguments.length){case 0:throw new Error("Not enough arguments");case 1:return a.mobservableStatic.props(b,b);case 2:for(var d in o)a.mobservableStatic.props(b,d,o[d]);break;case 3:var e=Array.isArray(c),f=a.mobservableStatic.value(c,b);Object.defineProperty(b,o,{get:e?function(){return f}:f,set:e?function(a){f.replace(a)}:f,enumerable:!0,configurable:!1})}return b},a.mobservableStatic.observable=function(b,c,d){var e=d?d.value:null;"function"==typeof e?(delete d.value,delete d.writable,d.get=function(){return a.mobservableStatic.props(this,c,e),this[c]},d.set=function(){throw console.trace(),new Error("It is not allowed to reassign observable functions")}):Object.defineProperty(b,c,{configurable:!1,enumberable:!0,get:function(){return a.mobservableStatic.props(this,c,void 0),this[c]},set:function(b){a.mobservableStatic.props(this,c,b)}})},a.mobservableStatic.toPlainValue=function p(a){if(a){if(a instanceof Array)return a.slice();if(a instanceof g)return a.get();if("function"==typeof a&&a.impl){if(a.impl instanceof g)return a();if(a.impl instanceof l)return a().slice()}else if("object"==typeof a){var b={};for(var c in a)b[c]=p(a[c]);return b}}return a},a.mobservableStatic.observeProperty=function(b,c,f,i){if(void 0===i&&(i=!1),!b||!c||void 0===b[c])throw new Error("Object '"+b+"' has no property '"+c+"'.");if(!f||"function"!=typeof f)throw new Error("Third argument to mobservable.observeProperty should be a function");var j=b[c];if(j instanceof g||j instanceof l)return j.observe(f,i);if(j.impl&&(j.impl instanceof g||j instanceof l))return j.impl.observe(f,i);var k=new h(function(){return b[c]},b),m=k.observe(f,i);return a.mobservableStatic.debugLevel&&0===k.dependencyState.observing.length&&d("mobservable.observeProperty: property '"+c+"' of '"+b+" doesn't seem to be observable. Did you define it as observable?"),e(function(){m(),k.dependencyState.dispose()})},a.mobservableStatic.watch=function q(a,b){var q=new i(a,b);return[q.value,function(){return q.dispose()}]},a.mobservableStatic.batch=function(a){return n.batch(a)},a.mobservableStatic.debugLevel=0;var f,g=function(){function a(a){this._value=a,this.changeEvent=new m,this.dependencyState=new j(this)}return a.prototype.set=function(a){if(a!==this._value){var b=this._value;this.dependencyState.markStale(),this._value=a,this.dependencyState.markReady(!0),this.changeEvent.emit(a,b)}},a.prototype.get=function(){return this.dependencyState.notifyObserved(),this._value},a.prototype.observe=function(a,b){var c=this;void 0===b&&(b=!1),this.dependencyState.setRefCount(1),b&&a(this.get(),void 0);var d=this.changeEvent.on(a);return e(function(){c.dependencyState.setRefCount(-1),d()})},a.prototype.createGetterSetter=function(){var a=this,b=this,c=function(a){return arguments.length>0?void b.set(a):b.get()};return c.observe=function(b,c){return a.observe(b,c)},c.impl=this,c.toString=function(){return a.toString()},c},a.prototype.toString=function(){return"Observable["+this._value+"]"},a}(),h=function(b){function c(a,c){if(b.call(this,void 0),this.func=a,this.scope=c,this.isComputing=!1,this.hasError=!1,"function"!=typeof a)throw new Error("ComputedObservable requires a function")}return __extends(c,b),c.prototype.get=function(){if(this.isComputing)throw new Error("Cycle detected");var b=this.dependencyState;if(b.isSleeping?j.trackingStack.length>0?(b.wakeUp(),b.notifyObserved()):this.compute():b.notifyObserved(),b.hasCycle)throw new Error("Cycle detected");if(this.hasError)throw a.mobservableStatic.debugLevel&&(console.trace(),d(this+": rethrowing caught exception to observer: "+this._value+(this._value.cause||""))),this._value;return this._value},c.prototype.set=function(a){throw new Error(this.toString()+": A computed observable does not accept new values!")},c.prototype.compute=function(){var a;try{if(this.isComputing)throw new Error("Cycle detected");this.isComputing=!0,a=this.func.call(this.scope),this.hasError=!1}catch(b){this.hasError=!0,console.error(this+"Caught error during computation: ",b),b instanceof Error?a=b:(a=new Error("MobservableComputationError"),a.cause=b)}if(this.isComputing=!1,a!==this._value){var c=this._value;return this._value=a,this.changeEvent.emit(a,c),!0}return!1},c.prototype.toString=function(){return"ComputedObservable["+this.func.toString()+"]"},c}(g),i=function(){function a(a,b){this.expr=a,this.onInvalidate=b,this.dependencyState=new j(this),this.didEvaluate=!1,this.dependencyState.computeNextState()}return a.prototype.compute=function(){return this.didEvaluate?(this.dispose(),this.onInvalidate()):(this.didEvaluate=!0,this.value=this.expr()),!1},a.prototype.dispose=function(){this.dependencyState.dispose()},a}();!function(a){a[a.STALE=0]="STALE",a[a.PENDING=1]="PENDING",a[a.READY=2]="READY"}(f||(f={}));var j=function(){function b(a){this.owner=a,this.state=f.READY,this.isSleeping=!0,this.hasCycle=!1,this.observing=[],this.prevObserving=null,this.observers=[],this.dependencyChangeCount=0,this.dependencyStaleCount=0,this.isDisposed=!1,this.externalRefenceCount=0,this.isComputed=void 0!==a.compute}return b.prototype.setRefCount=function(a){var b=this.externalRefenceCount+=a;0===b?this.tryToSleep():b===a&&this.wakeUp()},b.prototype.addObserver=function(a){this.observers[this.observers.length]=a},b.prototype.removeObserver=function(a){var b=this.observers,c=b.indexOf(a);-1!==c&&(b.splice(c,1),0===b.length&&this.tryToSleep())},b.prototype.markStale=function(){this.state===f.READY&&(this.state=f.STALE,this.notifyObservers())},b.prototype.markReady=function(a){this.state!==f.READY&&(this.state=f.READY,this.notifyObservers(a))},b.prototype.notifyObservers=function(a){void 0===a&&(a=!1);for(var b=this.observers.slice(),c=b.length,d=0;c>d;d++)b[d].notifyStateChange(this,a)},b.prototype.tryToSleep=function(){if(!this.isSleeping&&this.isComputed&&0===this.observers.length&&0===this.externalRefenceCount){for(var a=0,b=this.observing.length;b>a;a++)this.observing[a].removeObserver(this);this.observing=[],this.isSleeping=!0}},b.prototype.wakeUp=function(){this.isSleeping&&this.isComputed&&(this.isSleeping=!1,this.state=f.PENDING,this.computeNextState())},b.prototype.notifyStateChange=function(a,b){var c=this;a.state===f.STALE?1===++this.dependencyStaleCount&&this.markStale():(b&&(this.dependencyChangeCount+=1),0===--this.dependencyStaleCount&&(this.state=f.PENDING,n.schedule(function(){c.dependencyChangeCount>0?c.computeNextState():c.markReady(!1),c.dependencyChangeCount=0})))},b.prototype.computeNextState=function(){this.trackDependencies();var a=this.owner.compute();this.bindDependencies(),this.markReady(a)},b.prototype.trackDependencies=function(){this.prevObserving=this.observing,b.trackingStack[b.trackingStack.length]=[]},b.prototype.bindDependencies=function(){this.observing=b.trackingStack.pop(),this.isComputed&&0===this.observing.length&&a.mobservableStatic.debugLevel>1&&!this.isDisposed&&(console.trace(),d("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"));var e=c(this.observing,this.prevObserving),f=e[0],g=e[1];this.prevObserving=null;for(var h=0,i=g.length;i>h;h++)g[h].removeObserver(this);this.hasCycle=!1;for(var h=0,i=f.length;i>h;h++)this.isComputed&&f[h].findCycle(this)?(this.hasCycle=!0,this.observing.splice(this.observing.indexOf(f[h]),1),f[h].hasCycle=!0):f[h].addObserver(this)},b.prototype.notifyObserved=function(){var a=b.trackingStack,c=a.length;if(c>0){var d=a[c-1],e=d.length;d[e-1]!==this&&d[e-2]!==this&&(d[e]=this)}},b.prototype.findCycle=function(a){var b=this.observing;if(-1!==b.indexOf(a))return!0;for(var c=b.length,d=0;c>d;d++)if(b[d].findCycle(a))return!0;return!1},b.prototype.dispose=function(){if(this.observers.length)throw new Error("Cannot dispose DNode; it is still being observed");if(this.observing)for(var a=this.observing.length,b=0;a>b;b++)this.observing[b].removeObserver(this);this.observing=null,this.isDisposed=!0},b.trackingStack=[],b}(),k=function(){function a(){}return a}();k.prototype=[];var l=function(b){function c(a){b.call(this),Object.defineProperties(this,{dependencyState:{enumerable:!1,value:new j(this)},_values:{enumerable:!1,value:a?a.slice():[]},changeEvent:{enumerable:!1,value:new m}}),a&&a.length&&this.updateLength(0,a.length)}return __extends(c,b),Object.defineProperty(c.prototype,"length",{get:function(){return this.dependencyState.notifyObserved(),this._values.length},set:function(a){if("number"!=typeof a||0>a)throw new Error("Out of range: "+a);var b=this._values.length;a!==b&&(a>b?this.spliceWithArray(b,0,new Array(a-b)):this.spliceWithArray(a,b-a))},enumerable:!0,configurable:!0}),c.prototype.updateLength=function(a,b){if(0>b)for(var d=a+b;a>d;d++)delete this[d];else if(b>0){a+b>c.OBSERVABLE_ARRAY_BUFFER_SIZE&&c.reserveArrayBuffer(a+b);for(var d=a,e=a+b;e>d;d++)Object.defineProperty(this,""+d,c.ENUMERABLE_PROPS[d])}},c.prototype.spliceWithArray=function(a,b,c){var d=this._values.length;if(!(void 0!==c&&0!==c.length||0!==b&&0!==d))return[];void 0===a?a=0:a>d?a=d:0>a&&(a=Math.max(0,d+a)),b=1===arguments.length?d-a:void 0===b||null===b?0:Math.max(0,Math.min(b,d-a)),void 0===c&&(c=[]);var e=c.length-b,f=(g=this._values).splice.apply(g,[a,b].concat(c));return this.updateLength(d,e),this.notifySplice(a,f,c),f;var g},c.prototype.notifyChildUpdate=function(a,b){this.notifyChanged(),this.changeEvent.emit({object:this,type:"update",index:a,oldValue:b})},c.prototype.notifySplice=function(a,b,c){(0!==b.length||0!==c.length)&&(this.notifyChanged(),this.changeEvent.emit({object:this,type:"splice",index:a,addedCount:c.length,removed:b}))},c.prototype.notifyChanged=function(){this.dependencyState.markStale(),this.dependencyState.markReady(!0)},c.prototype.observe=function(a,b){return void 0===b&&(b=!1),b&&a({object:this,type:"splice",index:0,addedCount:this._values.length,removed:[]}),this.changeEvent.on(a)},c.prototype.clear=function(){return this.splice(0)},c.prototype.replace=function(a){return this.spliceWithArray(0,this._values.length,a)},c.prototype.values=function(){return this.dependencyState.notifyObserved(),this._values.slice()},c.prototype.toJSON=function(){return this.dependencyState.notifyObserved(),this._values.slice()},c.prototype.clone=function(){return this.dependencyState.notifyObserved(),new c(this._values)},c.prototype.find=function(a,b,c){void 0===c&&(c=0),this.dependencyState.notifyObserved();for(var d=this._values,e=d.length,f=c;e>f;f++)if(a.call(b,d[f],f,this))return d[f];return null},c.prototype.splice=function(a,b){for(var c=[],d=2;d<arguments.length;d++)c[d-2]=arguments[d];switch(this.sideEffectWarning("splice"),arguments.length){case 0:return[];case 1:return this.spliceWithArray(a);case 2:return this.spliceWithArray(a,b)}return this.spliceWithArray(a,b,c)},c.prototype.push=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("push"),this.spliceWithArray(this._values.length,0,a),this._values.length},c.prototype.pop=function(){return this.sideEffectWarning("pop"),this.splice(Math.max(this._values.length-1,0),1)[0]},c.prototype.shift=function(){return this.sideEffectWarning("shift"),this.splice(0,1)[0]},c.prototype.unshift=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("unshift"),this.spliceWithArray(0,0,a),this._values.length},c.prototype.reverse=function(){return this.sideEffectWarning("reverse"),this.replace(this._values.reverse())},c.prototype.sort=function(a){return this.sideEffectWarning("sort"),this.replace(this._values.sort.apply(this._values,arguments))},c.prototype.remove=function(a){this.sideEffectWarning("remove");var b=this._values.indexOf(a);return b>-1?(this.splice(b,1),!0):!1},c.prototype.toString=function(){return this.wrapReadFunction("toString",arguments)},c.prototype.toLocaleString=function(){return this.wrapReadFunction("toLocaleString",arguments)},c.prototype.concat=function(){return this.wrapReadFunction("concat",arguments)},c.prototype.join=function(a){return this.wrapReadFunction("join",arguments)},c.prototype.slice=function(a,b){return this.wrapReadFunction("slice",arguments)},c.prototype.indexOf=function(a,b){return this.wrapReadFunction("indexOf",arguments)},c.prototype.lastIndexOf=function(a,b){return this.wrapReadFunction("lastIndexOf",arguments)},c.prototype.every=function(a,b){return this.wrapReadFunction("every",arguments)},c.prototype.some=function(a,b){return this.wrapReadFunction("some",arguments)},c.prototype.forEach=function(a,b){return this.wrapReadFunction("forEach",arguments)},c.prototype.map=function(a,b){return this.wrapReadFunction("map",arguments)},c.prototype.filter=function(a,b){return this.wrapReadFunction("filter",arguments)},c.prototype.reduce=function(a,b){return this.wrapReadFunction("reduce",arguments)},c.prototype.reduceRight=function(a,b){return this.wrapReadFunction("reduceRight",arguments)},c.prototype.wrapReadFunction=function(a,b){var d=Array.prototype[a];return(c.prototype[a]=function(){return this.dependencyState.notifyObserved(),d.apply(this._values,arguments)}).apply(this,b)},c.prototype.sideEffectWarning=function(b){a.mobservableStatic.debugLevel>0&&j.trackingStack.length>0&&d("[Mobservable.Array] The method array."+b+" should probably not be used inside observable functions since it has side-effects")},c.createArrayBufferItem=function(a){var b={enumerable:!1,configurable:!1,set:function(b){if(a<this._values.length){var c=this._values[a];c!==b&&(this._values[a]=b,this.notifyChildUpdate(a,c))}else{if(a!==this._values.length)throw new Error("ObservableArray: Index out of bounds, "+a+" is larger than "+this.values.length);this.push(b)}},get:function(){return a<this._values.length?(this.dependencyState.notifyObserved(),this._values[a]):void 0}};Object.defineProperty(c.prototype,""+a,b),b.enumerable=!0,b.configurable=!0,c.ENUMERABLE_PROPS[a]=b},c.reserveArrayBuffer=function(a){for(var b=c.OBSERVABLE_ARRAY_BUFFER_SIZE;a>b;b++)c.createArrayBufferItem(b);c.OBSERVABLE_ARRAY_BUFFER_SIZE=a},c.OBSERVABLE_ARRAY_BUFFER_SIZE=0,c.ENUMERABLE_PROPS=[],c}(k);l.reserveArrayBuffer(1e3);var m=function(){function a(){this.listeners=[]}return a.prototype.emit=function(){var a=this.listeners.slice(),b=a.length;switch(arguments.length){case 0:for(var c=0;b>c;c++)a[c]();break;case 1:for(var d=arguments[0],c=0;b>c;c++)a[c](d);break;default:for(var c=0;b>c;c++)a[c].apply(null,arguments)}},a.prototype.on=function(a){var b=this;return this.listeners.push(a),e(function(){var c=b.listeners.indexOf(a);-1!==c&&b.listeners.splice(c,1)})},a.prototype.once=function(a){var b=this.on(function(){b(),a.apply(this,arguments)});return b},a}();a.mobservableStatic.SimpleEventEmitter=m;var n=function(){function a(){}return a.schedule=function(b){a.inBatch<1?b():a.tasks[a.tasks.length]=b},a.runPostBatchActions=function(){for(var b=0;a.tasks.length;)try{for(;b<a.tasks.length;b++)a.tasks[b]();a.tasks=[]}catch(c){console.error("Failed to run scheduled action, the action has been dropped from the queue: "+c,c),a.tasks.splice(0,b+1)}},a.batch=function(b){a.inBatch+=1;try{return b()}finally{0===--a.inBatch&&(a.inBatch+=1,a.runPostBatchActions(),a.inBatch-=1)}},a.inBatch=0,a.tasks=[],a}();a.mobservableStatic.ObserverMixin={componentWillMount:function(){var b=this.render;this.render=function(){var c=this;this._watchDisposer&&this._watchDisposer();var d=a.mobservableStatic.watch(function(){return b.call(c)},function(){c.forceUpdate()}),e=d[0],f=d[1];return this._watchDisposer=f,e}},componentWillUnmount:function(){this._watchDisposer&&this._watchDisposer()}},a.mobservableStatic.quickDiff=c,a.mobservableStatic.stackDepth=function(){return j.trackingStack.length}}(mobservable||(mobservable={})),function(a,b){"function"==typeof define&&define.amd?define("mobservable",[],function(){return b()}):"object"==typeof exports?module.exports=b():a.mobservable=b()}(this,function(){return mobservable.mobservableStatic});
var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},mobservable;!function(a){function b(b,c){return Array.isArray(b)?new l(b):"function"==typeof b?a.mobservableStatic.computed(b,c):a.mobservableStatic.primitive(b)}function c(a,b){if(!b.length)return[a,[]];if(!a.length)return[[],b];for(var c=[],d=[],e=0,f=0,g=a.length,h=!1,i=0,j=0,k=b.length,l=!1,m=!1;!m&&!h;){if(!l){if(g>e&&k>i&&a[e]===b[i]){if(e++,i++,e===g&&i===k)return[c,d];continue}f=e,j=i,l=!0}j+=1,f+=1,j>=k&&(m=!0),f>=g&&(h=!0),h||a[f]!==b[i]?m||b[j]!==a[e]||(d.push.apply(d,b.slice(i,j)),i=j+1,e++,l=!1):(c.push.apply(c,a.slice(e,f)),e=f+1,i++,l=!1)}return c.push.apply(c,a.slice(e)),d.push.apply(d,b.slice(i)),[c,d]}function d(a){console&&console.warn("[WARNING:mobservable] "+a)}function e(a){var b=!1;return function(){return b?void 0:(b=!0,a.apply(this,arguments))}}a.mobservableStatic=function(a,c){return b(a,c)},a.mobservableStatic.value=b,a.mobservableStatic.primitive=a.mobservableStatic.reference=function(a){return new g(a).createGetterSetter()},a.mobservableStatic.computed=function(a,b){return new h(a,b).createGetterSetter()},a.mobservableStatic.expr=function(a,b){if(0===j.trackingStack.length)throw new Error("mobservable.expr can only be used inside a computed observable. Probably mobservable.computed should be used instead of .expr");return new h(a,b).get()},a.mobservableStatic.array=function(a){return new l(a)},a.mobservableStatic.props=function o(b,o,c){switch(arguments.length){case 0:throw new Error("Not enough arguments");case 1:return a.mobservableStatic.props(b,b);case 2:for(var d in o)a.mobservableStatic.props(b,d,o[d]);break;case 3:var e=Array.isArray(c),f=a.mobservableStatic.value(c,b);Object.defineProperty(b,o,{get:e?function(){return f}:f,set:e?function(a){f.replace(a)}:f,enumerable:!0,configurable:!1})}return b},a.mobservableStatic.observable=function(b,c,d){var e=d?d.value:null;"function"==typeof e?(delete d.value,delete d.writable,d.get=function(){var b=this.key=a.mobservableStatic.computed(e,this);return b},d.set=function(){throw console.trace(),new Error("It is not allowed to reassign observable functions")}):Object.defineProperty(b,c,{configurable:!1,enumberable:!0,get:function(){return a.mobservableStatic.props(this,c,void 0),this[c]},set:function(b){a.mobservableStatic.props(this,c,b)}})},a.mobservableStatic.toPlainValue=function p(a){if(a){if(a instanceof Array)return a.slice();if(a instanceof g)return a.get();if("function"==typeof a&&a.impl){if(a.impl instanceof g)return a();if(a.impl instanceof l)return a().slice()}else if("object"==typeof a){var b={};for(var c in a)b[c]=p(a[c]);return b}}return a},a.mobservableStatic.observeProperty=function(b,c,f,i){if(void 0===i&&(i=!1),!b||!c||void 0===b[c])throw new Error("Object '"+b+"' has no property '"+c+"'.");if(!f||"function"!=typeof f)throw new Error("Third argument to mobservable.observeProperty should be a function");var j=b[c];if(j instanceof g||j instanceof l)return j.observe(f,i);if(j.impl&&(j.impl instanceof g||j instanceof l))return j.impl.observe(f,i);var k=new h(function(){return b[c]},b),m=k.observe(f,i);return a.mobservableStatic.debugLevel&&0===k.dependencyState.observing.length&&d("mobservable.observeProperty: property '"+c+"' of '"+b+" doesn't seem to be observable. Did you define it as observable?"),e(function(){m(),k.dependencyState.dispose()})},a.mobservableStatic.watch=function q(a,b){var q=new i(a,b);return[q.value,function(){return q.dispose()}]},a.mobservableStatic.batch=function(a){return n.batch(a)},a.mobservableStatic.debugLevel=0;var f,g=function(){function a(a){this._value=a,this.changeEvent=new m,this.dependencyState=new j(this)}return a.prototype.set=function(a){if(a!==this._value){var b=this._value;this.dependencyState.markStale(),this._value=a,this.dependencyState.markReady(!0),this.changeEvent.emit(a,b)}},a.prototype.get=function(){return this.dependencyState.notifyObserved(),this._value},a.prototype.observe=function(a,b){var c=this;void 0===b&&(b=!1),this.dependencyState.setRefCount(1),b&&a(this.get(),void 0);var d=this.changeEvent.on(a);return e(function(){c.dependencyState.setRefCount(-1),d()})},a.prototype.createGetterSetter=function(){var a=this,b=this,c=function(a){return arguments.length>0?void b.set(a):b.get()};return c.observe=function(b,c){return a.observe(b,c)},c.impl=this,c.toString=function(){return a.toString()},c},a.prototype.toString=function(){return"Observable["+this._value+"]"},a}(),h=function(b){function c(a,c){if(b.call(this,void 0),this.func=a,this.scope=c,this.isComputing=!1,this.hasError=!1,"function"!=typeof a)throw new Error("ComputedObservable requires a function")}return __extends(c,b),c.prototype.get=function(){if(this.isComputing)throw new Error("Cycle detected");var b=this.dependencyState;if(b.isSleeping?j.trackingStack.length>0?(b.wakeUp(),b.notifyObserved()):this.compute():b.notifyObserved(),b.hasCycle)throw new Error("Cycle detected");if(this.hasError)throw a.mobservableStatic.debugLevel&&(console.trace(),d(this+": rethrowing caught exception to observer: "+this._value+(this._value.cause||""))),this._value;return this._value},c.prototype.set=function(a){throw new Error(this.toString()+": A computed observable does not accept new values!")},c.prototype.compute=function(){var a;try{if(this.isComputing)throw new Error("Cycle detected");this.isComputing=!0,a=this.func.call(this.scope),this.hasError=!1}catch(b){this.hasError=!0,console.error(this+"Caught error during computation: ",b),b instanceof Error?a=b:(a=new Error("MobservableComputationError"),a.cause=b)}if(this.isComputing=!1,a!==this._value){var c=this._value;return this._value=a,this.changeEvent.emit(a,c),!0}return!1},c.prototype.toString=function(){return"ComputedObservable["+this.func.toString()+"]"},c}(g),i=function(){function a(a,b){this.expr=a,this.onInvalidate=b,this.dependencyState=new j(this),this.didEvaluate=!1,this.dependencyState.computeNextState()}return a.prototype.compute=function(){return this.didEvaluate?(this.dispose(),this.onInvalidate()):(this.didEvaluate=!0,this.value=this.expr()),!1},a.prototype.dispose=function(){this.dependencyState.dispose()},a}();!function(a){a[a.STALE=0]="STALE",a[a.PENDING=1]="PENDING",a[a.READY=2]="READY"}(f||(f={}));var j=function(){function b(a){this.owner=a,this.state=f.READY,this.isSleeping=!0,this.hasCycle=!1,this.observing=[],this.prevObserving=null,this.observers=[],this.dependencyChangeCount=0,this.dependencyStaleCount=0,this.isDisposed=!1,this.externalRefenceCount=0,this.isComputed=void 0!==a.compute}return b.prototype.setRefCount=function(a){var b=this.externalRefenceCount+=a;0===b?this.tryToSleep():b===a&&this.wakeUp()},b.prototype.addObserver=function(a){this.observers[this.observers.length]=a},b.prototype.removeObserver=function(a){var b=this.observers,c=b.indexOf(a);-1!==c&&(b.splice(c,1),0===b.length&&this.tryToSleep())},b.prototype.markStale=function(){this.state===f.READY&&(this.state=f.STALE,this.notifyObservers())},b.prototype.markReady=function(a){this.state!==f.READY&&(this.state=f.READY,this.notifyObservers(a))},b.prototype.notifyObservers=function(a){void 0===a&&(a=!1);for(var b=this.observers.slice(),c=b.length,d=0;c>d;d++)b[d].notifyStateChange(this,a)},b.prototype.tryToSleep=function(){if(!this.isSleeping&&this.isComputed&&0===this.observers.length&&0===this.externalRefenceCount){for(var a=0,b=this.observing.length;b>a;a++)this.observing[a].removeObserver(this);this.observing=[],this.isSleeping=!0}},b.prototype.wakeUp=function(){this.isSleeping&&this.isComputed&&(this.isSleeping=!1,this.state=f.PENDING,this.computeNextState())},b.prototype.notifyStateChange=function(a,b){var c=this;a.state===f.STALE?1===++this.dependencyStaleCount&&this.markStale():(b&&(this.dependencyChangeCount+=1),0===--this.dependencyStaleCount&&(this.state=f.PENDING,n.schedule(function(){c.dependencyChangeCount>0?c.computeNextState():c.markReady(!1),c.dependencyChangeCount=0})))},b.prototype.computeNextState=function(){this.trackDependencies();var a=this.owner.compute();this.bindDependencies(),this.markReady(a)},b.prototype.trackDependencies=function(){this.prevObserving=this.observing,b.trackingStack[b.trackingStack.length]=[]},b.prototype.bindDependencies=function(){this.observing=b.trackingStack.pop(),this.isComputed&&0===this.observing.length&&a.mobservableStatic.debugLevel>1&&!this.isDisposed&&(console.trace(),d("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"));var e=c(this.observing,this.prevObserving),f=e[0],g=e[1];this.prevObserving=null;for(var h=0,i=g.length;i>h;h++)g[h].removeObserver(this);this.hasCycle=!1;for(var h=0,i=f.length;i>h;h++)this.isComputed&&f[h].findCycle(this)?(this.hasCycle=!0,this.observing.splice(this.observing.indexOf(f[h]),1),f[h].hasCycle=!0):f[h].addObserver(this)},b.prototype.notifyObserved=function(){var a=b.trackingStack,c=a.length;if(c>0){var d=a[c-1],e=d.length;d[e-1]!==this&&d[e-2]!==this&&(d[e]=this)}},b.prototype.findCycle=function(a){var b=this.observing;if(-1!==b.indexOf(a))return!0;for(var c=b.length,d=0;c>d;d++)if(b[d].findCycle(a))return!0;return!1},b.prototype.dispose=function(){if(this.observers.length)throw new Error("Cannot dispose DNode; it is still being observed");if(this.observing)for(var a=this.observing.length,b=0;a>b;b++)this.observing[b].removeObserver(this);this.observing=null,this.isDisposed=!0},b.trackingStack=[],b}(),k=function(){function a(){}return a}();k.prototype=[];var l=function(b){function c(a){b.call(this),Object.defineProperties(this,{dependencyState:{enumerable:!1,value:new j(this)},_values:{enumerable:!1,value:a?a.slice():[]},changeEvent:{enumerable:!1,value:new m}}),a&&a.length&&this.updateLength(0,a.length)}return __extends(c,b),Object.defineProperty(c.prototype,"length",{get:function(){return this.dependencyState.notifyObserved(),this._values.length},set:function(a){if("number"!=typeof a||0>a)throw new Error("Out of range: "+a);var b=this._values.length;a!==b&&(a>b?this.spliceWithArray(b,0,new Array(a-b)):this.spliceWithArray(a,b-a))},enumerable:!0,configurable:!0}),c.prototype.updateLength=function(a,b){if(0>b)for(var d=a+b;a>d;d++)delete this[d];else if(b>0){a+b>c.OBSERVABLE_ARRAY_BUFFER_SIZE&&c.reserveArrayBuffer(a+b);for(var d=a,e=a+b;e>d;d++)Object.defineProperty(this,""+d,c.ENUMERABLE_PROPS[d])}},c.prototype.spliceWithArray=function(a,b,c){var d=this._values.length;if(!(void 0!==c&&0!==c.length||0!==b&&0!==d))return[];void 0===a?a=0:a>d?a=d:0>a&&(a=Math.max(0,d+a)),b=1===arguments.length?d-a:void 0===b||null===b?0:Math.max(0,Math.min(b,d-a)),void 0===c&&(c=[]);var e=c.length-b,f=(g=this._values).splice.apply(g,[a,b].concat(c));return this.updateLength(d,e),this.notifySplice(a,f,c),f;var g},c.prototype.notifyChildUpdate=function(a,b){this.notifyChanged(),this.changeEvent.emit({object:this,type:"update",index:a,oldValue:b})},c.prototype.notifySplice=function(a,b,c){(0!==b.length||0!==c.length)&&(this.notifyChanged(),this.changeEvent.emit({object:this,type:"splice",index:a,addedCount:c.length,removed:b}))},c.prototype.notifyChanged=function(){this.dependencyState.markStale(),this.dependencyState.markReady(!0)},c.prototype.observe=function(a,b){return void 0===b&&(b=!1),b&&a({object:this,type:"splice",index:0,addedCount:this._values.length,removed:[]}),this.changeEvent.on(a)},c.prototype.clear=function(){return this.splice(0)},c.prototype.replace=function(a){return this.spliceWithArray(0,this._values.length,a)},c.prototype.values=function(){return this.dependencyState.notifyObserved(),this._values.slice()},c.prototype.toJSON=function(){return this.dependencyState.notifyObserved(),this._values.slice()},c.prototype.clone=function(){return this.dependencyState.notifyObserved(),new c(this._values)},c.prototype.find=function(a,b,c){void 0===c&&(c=0),this.dependencyState.notifyObserved();for(var d=this._values,e=d.length,f=c;e>f;f++)if(a.call(b,d[f],f,this))return d[f];return null},c.prototype.splice=function(a,b){for(var c=[],d=2;d<arguments.length;d++)c[d-2]=arguments[d];switch(this.sideEffectWarning("splice"),arguments.length){case 0:return[];case 1:return this.spliceWithArray(a);case 2:return this.spliceWithArray(a,b)}return this.spliceWithArray(a,b,c)},c.prototype.push=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("push"),this.spliceWithArray(this._values.length,0,a),this._values.length},c.prototype.pop=function(){return this.sideEffectWarning("pop"),this.splice(Math.max(this._values.length-1,0),1)[0]},c.prototype.shift=function(){return this.sideEffectWarning("shift"),this.splice(0,1)[0]},c.prototype.unshift=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("unshift"),this.spliceWithArray(0,0,a),this._values.length},c.prototype.reverse=function(){return this.sideEffectWarning("reverse"),this.replace(this._values.reverse())},c.prototype.sort=function(a){return this.sideEffectWarning("sort"),this.replace(this._values.sort.apply(this._values,arguments))},c.prototype.remove=function(a){this.sideEffectWarning("remove");var b=this._values.indexOf(a);return b>-1?(this.splice(b,1),!0):!1},c.prototype.toString=function(){return this.wrapReadFunction("toString",arguments)},c.prototype.toLocaleString=function(){return this.wrapReadFunction("toLocaleString",arguments)},c.prototype.concat=function(){return this.wrapReadFunction("concat",arguments)},c.prototype.join=function(a){return this.wrapReadFunction("join",arguments)},c.prototype.slice=function(a,b){return this.wrapReadFunction("slice",arguments)},c.prototype.indexOf=function(a,b){return this.wrapReadFunction("indexOf",arguments)},c.prototype.lastIndexOf=function(a,b){return this.wrapReadFunction("lastIndexOf",arguments)},c.prototype.every=function(a,b){return this.wrapReadFunction("every",arguments)},c.prototype.some=function(a,b){return this.wrapReadFunction("some",arguments)},c.prototype.forEach=function(a,b){return this.wrapReadFunction("forEach",arguments)},c.prototype.map=function(a,b){return this.wrapReadFunction("map",arguments)},c.prototype.filter=function(a,b){return this.wrapReadFunction("filter",arguments)},c.prototype.reduce=function(a,b){return this.wrapReadFunction("reduce",arguments)},c.prototype.reduceRight=function(a,b){return this.wrapReadFunction("reduceRight",arguments)},c.prototype.wrapReadFunction=function(a,b){var d=Array.prototype[a];return(c.prototype[a]=function(){return this.dependencyState.notifyObserved(),d.apply(this._values,arguments)}).apply(this,b)},c.prototype.sideEffectWarning=function(b){a.mobservableStatic.debugLevel>0&&j.trackingStack.length>0&&d("[Mobservable.Array] The method array."+b+" should probably not be used inside observable functions since it has side-effects")},c.createArrayBufferItem=function(a){var b={enumerable:!1,configurable:!1,set:function(b){if(a<this._values.length){var c=this._values[a];c!==b&&(this._values[a]=b,this.notifyChildUpdate(a,c))}else{if(a!==this._values.length)throw new Error("ObservableArray: Index out of bounds, "+a+" is larger than "+this.values.length);this.push(b)}},get:function(){return a<this._values.length?(this.dependencyState.notifyObserved(),this._values[a]):void 0}};Object.defineProperty(c.prototype,""+a,b),b.enumerable=!0,b.configurable=!0,c.ENUMERABLE_PROPS[a]=b},c.reserveArrayBuffer=function(a){for(var b=c.OBSERVABLE_ARRAY_BUFFER_SIZE;a>b;b++)c.createArrayBufferItem(b);c.OBSERVABLE_ARRAY_BUFFER_SIZE=a},c.OBSERVABLE_ARRAY_BUFFER_SIZE=0,c.ENUMERABLE_PROPS=[],c}(k);l.reserveArrayBuffer(1e3);var m=function(){function a(){this.listeners=[]}return a.prototype.emit=function(){var a=this.listeners.slice(),b=a.length;switch(arguments.length){case 0:for(var c=0;b>c;c++)a[c]();break;case 1:for(var d=arguments[0],c=0;b>c;c++)a[c](d);break;default:for(var c=0;b>c;c++)a[c].apply(null,arguments)}},a.prototype.on=function(a){var b=this;return this.listeners.push(a),e(function(){var c=b.listeners.indexOf(a);-1!==c&&b.listeners.splice(c,1)})},a.prototype.once=function(a){var b=this.on(function(){b(),a.apply(this,arguments)});return b},a}();a.mobservableStatic.SimpleEventEmitter=m;var n=function(){function a(){}return a.schedule=function(b){a.inBatch<1?b():a.tasks[a.tasks.length]=b},a.runPostBatchActions=function(){for(var b=0;a.tasks.length;)try{for(;b<a.tasks.length;b++)a.tasks[b]();a.tasks=[]}catch(c){console.error("Failed to run scheduled action, the action has been dropped from the queue: "+c,c),a.tasks.splice(0,b+1)}},a.batch=function(b){a.inBatch+=1;try{return b()}finally{0===--a.inBatch&&(a.inBatch+=1,a.runPostBatchActions(),a.inBatch-=1)}},a.inBatch=0,a.tasks=[],a}();a.mobservableStatic.ObserverMixin={componentWillMount:function(){var b=this.render;this.render=function(){var c=this;this._watchDisposer&&this._watchDisposer();var e=a.mobservableStatic.watch(function(){return b.call(c)},function(){c.isMounted()?c.forceUpdate():a.mobservableStatic.debugLevel&&d("Rendering was triggered for unmounted component. Please check the lifecycle of the components")}),f=e[0],g=e[1];return this._watchDisposer=g,f}},componentWillUnmount:function(){this._watchDisposer&&this._watchDisposer()},shouldComponentUpdate:function(a,b){if(this.state!==b)return!0;var c,d=Object.keys(this.props);if(d.length!==Object.keys(a).length)return!0;for(var e=d.length-1;c=d[e];e--)if(a[c]!==this.props[c])return!0;return!1}},a.mobservableStatic.ObservingComponent=function(b){var c=b.componentWillMount,d=b.componentWillUnmount;return b.prototype.componentWillMount=function(){return a.mobservableStatic.ObserverMixin.componentWillMount.apply(this,arguments),c&&c.apply(this,arguments)},b.prototype.componentWillUnmount=function(){return a.mobservableStatic.ObserverMixin.componentWillUnmount.apply(this,arguments),d&&d.apply(this,arguments)},b.prototype.shouldComponentUpdate=a.mobservableStatic.ObserverMixin.shouldComponentUpdate,b},a.mobservableStatic.quickDiff=c,a.mobservableStatic.stackDepth=function(){return j.trackingStack.length}}(mobservable||(mobservable={})),function(a,b){"function"==typeof define&&define.amd?define("mobservable",[],function(){return b()}):"object"==typeof exports?module.exports=b():a.mobservable=b()}(this,function(){return mobservable.mobservableStatic});

@@ -19,3 +19,4 @@ /** GENERATED FILE */

reference<T>(value?:T):Mobservable.IObservableValue<T>;
computed<T>(value:()=>T,scope?):Mobservable.IObservableValue<T>;
computed<T>(func:()=>T,scope?):Mobservable.IObservableValue<T>;
expr<T>(expr:()=>T,scope?):T;

@@ -45,3 +46,5 @@ // create observable properties

componentWillUnmount();
}
shouldComponentUpdate(nextProps, nextState);
};
ObservingComponent<T>(componentClass:T):T;
}

@@ -48,0 +51,0 @@

@@ -18,3 +18,4 @@ /**

reference<T>(value?:T):Mobservable.IObservableValue<T>;
computed<T>(value:()=>T,scope?):Mobservable.IObservableValue<T>;
computed<T>(func:()=>T,scope?):Mobservable.IObservableValue<T>;
expr<T>(expr:()=>T,scope?):T;

@@ -44,3 +45,5 @@ // create observable properties

componentWillUnmount();
}
shouldComponentUpdate(nextProps, nextState);
};
ObservingComponent<T>(componentClass:T):T;
}

@@ -127,2 +130,8 @@

mobservableStatic.expr = function<T>(expr:()=>void, scope?) {
if (DNode.trackingStack.length === 0)
throw new Error("mobservable.expr can only be used inside a computed observable. Probably mobservable.computed should be used instead of .expr");
return new ComputedObservable(expr, scope).get();
}
mobservableStatic.array = function array<T>(values?:T[]): ObservableArray<T> {

@@ -179,9 +188,9 @@ return new ObservableArray(values);

descriptor.get = function() {
mobservableStatic.props(this, key, baseValue);
return this[key];
}
var observable = this.key = mobservableStatic.computed(baseValue, this);
return observable;
};
descriptor.set = function () {
console.trace();
throw new Error("It is not allowed to reassign observable functions");
}
};
} else {

@@ -473,3 +482,3 @@ Object.defineProperty(target, key, {

this.tryToSleep();
else if (rc === delta)
else if (rc === delta) // a.k.a. rc was zero.
this.wakeUp();

@@ -992,3 +1001,6 @@ }

var[rendering, disposer] = mobservableStatic.watch(() => baseRender.call(this), () => {
this.forceUpdate();
if (this.isMounted())
this.forceUpdate();
else if (mobservableStatic.debugLevel)
warn("Rendering was triggered for unmounted component. Please check the lifecycle of the components");
});

@@ -1003,5 +1015,35 @@ this._watchDisposer = disposer;

this._watchDisposer();
},
shouldComponentUpdate: function(nextProps, nextState) {
// update on any state changes (as is the default)
if (this.state !== nextState)
return true;
// update if props are shallowly not equal, inspired by PureRenderMixin
var keys = Object.keys(this.props);
var key;
if (keys.length !== Object.keys(nextProps).length)
return true;
for(var i = keys.length -1; i >= 0, key = keys[i]; i--)
if (nextProps[key] !== this.props[key])
return true;
return false;
}
}
mobservableStatic.ObservingComponent = function(componentClass) {
var baseMount = componentClass.componentWillMount;
var baseUnmount = componentClass.componentWillUnmount;
componentClass.prototype.componentWillMount = function() {
mobservableStatic.ObserverMixin.componentWillMount.apply(this, arguments);
return baseMount && baseMount.apply(this, arguments);
};
componentClass.prototype.componentWillUnmount = function() {
mobservableStatic.ObserverMixin.componentWillUnmount.apply(this, arguments);
return baseUnmount && baseUnmount.apply(this, arguments);
};
componentClass.prototype.shouldComponentUpdate = mobservableStatic.ObserverMixin.shouldComponentUpdate;
return componentClass;
};
/**

@@ -1008,0 +1050,0 @@ * Given a new and an old list, tries to determine which items are added or removed

{
"name": "mobservable",
"version": "0.4.3",
"version": "0.5.0",
"description": "Changes are coming! Small library for creating observable properties, arrays and functions",

@@ -28,3 +28,2 @@ "main": "dist/mobservable.js",

"nodeunit-browser-tap": "^0.1.0",
"nscript": "^0.1.5",
"typescript": "^1.5.0-beta"

@@ -31,0 +30,0 @@ },

@@ -8,12 +8,23 @@ # MOBservable

MOBservable is light-weight stand-alone observable implementation, that helps you to create reactive data structures, based on the ideas of observables in bigger frameworks like `knockout`, `ember`, but this time without 'strings attached'.
MOBservables allows you to observe primitive values, references, functions and arrays and makes sure that all changes in your data are propagated automatically, atomically and synchronously.
MOBservable is light-weight stand-alone library to create reactive primitives, functions, arrays and objects.
[Blog post: combining React with MOBservable](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/)
Its goal is to make developers happy and productive, by removing boilerplate work such as invalidating derived data or managing event listeners.
It makes sure data changes are automatically, atomically and synchronously propagated through your app without being obtrusive.
MOBservable runs in any ES5 environment but features also some React addons.
It is higly efficient and shines when managing large amounts of complex, cyclic, nested or computed data.
* [Blog post: combining React with MOBservable](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/)
* [Examples](#examples)
* [Design principles](#design-principles)
* [API documentation](#api-documentation)
* [Advanced Tips & Tricks](#advanced-tips--tricks)
# Examples
[Fiddle demo: MOBservable + JQuery](http://jsfiddle.net/mweststrate/vxn7qgdw)
[Fiddle demo: MOBservable + React](https://jsfiddle.net/mweststrate/46vL0phw)
* [Fiddle demo: MOBservable + React: simple timer](https://jsfiddle.net/mweststrate/wgbe4guu/)
* [Fiddle demo: MOBservable + React: shop](https://jsfiddle.net/mweststrate/46vL0phw)
* [Fiddle demo: MOBservable + JQuery: shop](http://jsfiddle.net/mweststrate/vxn7qgdw)
The source of all demo's can also be found in the [example](/example) folder.
## Example: Observable values and functions

@@ -69,3 +80,3 @@

// (computed) properties can be accessed like any other property:
console.log(jan.fullName);
console.log(jane.fullName);
// prints: "Jan Dôh"

@@ -83,3 +94,3 @@

`mobservable` provides an observable array implementation, which is fully ES5 compliant,
`mobservable` provides an observable array implementation (as ES7 polyfill), which is fully ES5 compliant,
but which will notify dependent computations upon each change.

@@ -149,34 +160,71 @@

## Example: ObserverMixin for react components
## Example: ObservingComponent for react components
MOBservable ships with a mixin that can be used to subscribe React components to observables automatically, so that model changes are processed transparently.
The full JSX example can be found in this [fjsiddle]()
MOBservable ships with a mixin and class decorator that can be used to subscribe React components to observables automatically.
The full JSX example can be found in this [fjsiddle](https://jsfiddle.net/mweststrate/wgbe4guu/)
```javascript
function Article(name, price) {
mobservable.props(this, {
name: name,
price: price
});
var store = {};
// add observable properties to the store
mobservable.props(store, {
timer: 0 // this could be an array, object, function as well..
});
// of course, this could be put flux-style in dispatchable actions, but this is just to demo Model -> View
function resetTimer() {
store.timer = 0;
}
var ArticleView = React.createClass({
mixins: [mobservable.ObserverMixin],
setInterval(function() {
store.timer += 1;
}, 1000);
// This component is actually an observer of all store properties that are accessed during the last rendering
// so there is no need to declare any data use, nor is there (seemingly) any state in this component
// the combination of mobservable.props and ObservingComponent does all the magic for us.
// UI updates are nowhere forced, but all views (un)subscribe to their data automatically
var TimerView = mobservable.ObservingComponent(React.createClass({
render: function() {
return (<li>
<span>{this.props.article.name}</span>
<span className="price">{this.props.article.price}</span>
</li>);
return (<span>Seconds passed: {this.props.store.timer}</span>);
}
}));
var TimerApp = React.createClass({
render: function() {
var now = new Date(); // just to demonstrate that TimerView updates independently of TimerApp
return (<div>
<div>Started rendering at: {now.toString()}</div>
<TimerView {...this.props} />
<br/><button onClick={resetTimer}>Reset timer</button>
</div>);
}
});
var book = new Article("Orthodoxy, G.K. Chesterton", 19.95);
React.render(<ArticleView article={book} />, document.body);
book.price = 15.95; // Triggers automatically a re-render of the ArticleView
// pass in the store to the component tree (you could also access it directly through global vars, whatever suits your style)
React.render(<TimerApp store={store} />, document.body);
```
# Processing observables
# Design principles
## Principles
MOBservable is designed with the following principles in mind.
- The Model, View (and Contorller) of an app should be separated.
Views should be loosely coupled to the UI, so that UI refactorings do not require changes of the data model.
It should be possible to describe views on the data model as naturally as possible, as-if data does not change over time.
- Derived data should be re-calculated automatically and efficiently.
It is the responsibility of MOBservable to prevent that views ever become stale.
- MOBservable is unobtrusive and doesnt place any constraints on how you build or work with data structures.
Inheritance, classes, cyclic data structures, or instance methods...? The library does not pose any restrictions on your data.
- Data should be mutable as this is close to the natural mental model of most kinds of data.
<small>(despite some nice properties of immutable data, mutable data is easier to inspect, read, grok and especially more natural to program against.
`markRead(email) { email.isRead = true; }` is more convenient to write than `markRead(email) { return { ...email, isRead : true }; }` or `markRead(email) { model.set('email', 'isRead', true); }`.
Especially when email is somewhere deep in your model tree)</small>
- Subscriptions should be a breeze to manage, and managed automatically wherever possible.
- MOBservable is only about the model data, not about querying, back-end communication etc (although observers are really useful there as well).
## Behavior
Observable values, arrays and functions created by `mobservable` possess the following characteristics:

@@ -187,7 +235,7 @@

* _real time dependency detection_. Computed values only depend on values actually used in the last computation, for example in this `a -> b > 5 ? c : b` the variable `c` will only cause a re-evaluation of a if `b` > 5.
* _lazy_. Computed values will only be evaluated if they are actually being observed. So make sure computed functions are pure and side effect free; the library might not evaluate the expression as often as you thought it would.
* _lazy_. Computed values will only be evaluated if they are actually being observed. So make sure computed functions are pure and side effect free; the library might not evaluate expressions as often as you thought it would.
* _cycle detection_. Cycles in computes, like in `a -> 2 * b; b -> 2 * a;` will be deteced automatically.
* _error handling_. Exceptions that are raised during computations are propagated to consumers.
# API
# API Documentation

@@ -228,3 +276,2 @@ [Typescript typings](https://github.com/mweststrate/MOBservable/blob/master/mobservable.d.ts)

### mobservable.reference

@@ -269,11 +316,23 @@

### mobservable.expr
`mobservable.expr<T>(expr:()=>T,scope?):T;`
This function is simply sugar for `mobservable.computed(expr, scope)();`.
`expr` can be used to split up and improve the performance of expensive computations,
as described in this [section](#use-nested-observables-in-expensive-computations).
### mobservable.array
`mobservable.array<T>(values? : T[]) : IObservableArray<T>`
**Note: ES5 environments only**
Constructs an array like, observable structure. An observable array is a thin abstraction over native arrays that adds observable properties.
The most notable difference between built-in arrays is that these arrays cannot be sparse, that is, values assigned to an index larger than `length` are considered out-of-bounds and not oberved (nor any other property that is assigned to a non-numeric index).
Constructs an array like, observable structure. An observable array is a thin abstraction over native arrays and adds observable properties.
The most notable difference between built-in arrays is that these arrays cannot be sparse, that is,
values assigned to an index larger than `length` are considered out-of-bounds and not oberved
(nor any other property that is assigned to a non-numeric pr negative index).
Furthermore, `Array.isArray(observableArray)` and `typeof observableArray === "array"` will yield `false` for observable arrays, but `observableArray instanceof Array` will return `true`.
Furthermore, `Array.isArray(observableArray)` and `typeof observableArray === "array"` will yield `false` for observable arrays,
but `observableArray instanceof Array` will return `true`.

@@ -300,3 +359,3 @@ ```javascript

* `replace(newItems:T[])` Replaces all existing entries in the array with new ones.
* `values(): T[]` Returns a shallow clone of the array, similar to `.slice`
* `values(): T[]` Returns a shallow, non-observable clone of the array, similar to `.slice`
* `clone(): IObservableArray<T>` Create a new observable array containing the same values

@@ -316,3 +375,3 @@ * `find(predicate:(item:T,index:number,array:IObservableArray<T>)=>boolean,thisArg?,fromIndex?:number):T` Find implementation, basically the same as the ES7 Array.find proposal, but with added `fromIndex` parameter.

Creates observable properties on the given `target` object. This function uses `mobservable.value` internally to create observables.
Creating properties has as advantage that they are more convenient to use. See also [props or variables](#value_versus_props).
Creating properties has as advantage that they are more convenient to use. See also [value versus props](#value-versus-props).
The original `target`, with the added properties, is returned by this function. Functions used to created computed observables will automatically

@@ -334,3 +393,4 @@ be bound to the correct `this`.

Note that observables created by `mobservable.props` do not expose an `.observe` method, to observe properties, see [`mobservable.observeProperty`](#mobservable_observeproperty)
Note that observables created by `mobservable.props` do not expose an `.observe` method,
to observe properties, see [`mobservable.observeProperty`](#mobservableobserveproperty)

@@ -405,3 +465,3 @@ Other forms in which this function can be called:

This is useful if you want to apply a bunch of different updates throughout your model before needing the updated computed values,
for example while refreshing a data from the database.
for example while refreshing a data from the database. In practice, you wil probably never need `.batch`, since observables usually update wickedly fast.

@@ -441,9 +501,23 @@ ```javascript

so that the component is re-rendered each time an observable has changed.
In general, this mixin combines very well with the [React PureRender mixin](https://facebook.github.io/react/docs/pure-render-mixin.html) if observable objects or arrays are passed into the component.
This mixin also prevents re-renderings when the *props* of the component have only shallowly changed
(Similar to [React PureRender mixin](https://facebook.github.io/react/docs/pure-render-mixin.html), except that *state* changes are still always processed).
This allows for React apps that perform well in apps with large amount of complex data, while avoiding the need to manage a lot of subscriptions.
See the [above example](#example_observermixin_for_react_components) or the [JSFiddle demo: MOBservable + React](https://jsfiddle.net/mweststrate/46vL0phw)
See the [above example](#example_observingcomponent_for_react_components) or the [JSFiddle demo: MOBservable + React](https://jsfiddle.net/mweststrate/46vL0phw)
For an extensive explanation, read [combing React with MOBservable](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/)
### mobservable.ObservingComponent
`mobservable.ObservingComponent(clazz:ReactComponentClass):ReactComponentClass`
If you want to create a React component based on ES6 where mixins are not supported,
you can use the `ObservingComponent` function to wrap around your React `createClass` call (instead of using the mixin `ObserverMixin`):
```javascript
// TODO: change to class
var myComponent = mobservable.ObservingComponent(React.createClass({
// widget specification without mixins
});
```
### mobservable.debugLevel

@@ -454,4 +528,5 @@

### mobservable.SimpleEventEmitter
Utility class for managing an event. Its methods are:
Utility class for managing an event. Its instance methods are:
* `new mobservable.SimpleEventEmitter()`. Creates a new `SimpleEventEmitter`
* `emit(...data : any[])`. Invokes all registered listeners with the given arguments

@@ -461,4 +536,8 @@ * `on(listener:(...data : any[]) => void) : () => void`. Registers a new callback that will be invoked on each `emit`. Returns a method that can be used to unsubscribe the listener.

# Tips & tricks
# Advanced Tips & Tricks
## How to create lazy values?
All computed values are lazy and only evaluated upon first observation (or when their value is explicitly getted)
## Use local variables in computations

@@ -491,2 +570,49 @@

## Use nested observables in expensive computations
It is perfectly fine to create computed observables inside computed observables.
This is a useful pattern if you have an expensive computation that depends on a condition check that is fired often, but not changed often.
For example when your computation contains a cheap treshold check, or when your UI renderig depends on the some selection of the user.
For example:
```javascript
var person; // ...
var total = mobservable(function() {
if (person.age === 42)
doSomeExpensiveComputation();
else
doSomeOtherExpensiveComputation();
});
```
In the example above, every single time the person's `age` changes, `total` is computed by invoking some expensive computations.
However, if the expression `page.age === 42` was put in a separate observable,
computing the `total` itself could be avoided in many cases because a recomputation would only occur if the value of the complete expression changes.
Yet, you might not want to create separate stand-alone observables for these expressions,
because you don't have a nice place to put them or because it would make the readability of the code worse.
In such cases you can also create an inline observable.
In the following example, the total is only recalculated if the age changes to, or from, 42. Which means that for most other ages,
recomputing the expensive computations can be avoided.
```javascript
var person; // ...
var total = mobservable(function() {
var ageEquals42 = mobservable(function() { return person.age === 42 })(); // create observable and invoke getter
if (ageEquals42)
doSomeExpensiveComputation();
else
doSomeOtherExpensiveComputation();
});
```
Note that the dangling `()` after the expression is meant to invoke the getter of the just created observable to obtain its value.
For convenience the same statement can also be rewritten using the [expr](#mobservableexpr) function:
```javascript
// ...
var ageEquals42 = mobservable.expr(function() { return person.age === 42 });
// ...
```
## Use native array methods

@@ -517,3 +643,3 @@

// Also fast:
// Faster:
var sum2 = mobservable(function() {

@@ -527,17 +653,22 @@ return numbers.reduce(function(a, b) { // single observable read

Using `mobservable.value` or `mobservable.props` to create observables inside objects might be a matter of taste.
The difference between `obj.amount = mobservable.value(3)` and `mobservable.props(obj, { value: 3 })`
to create observable values inside an object might seem to be a matter of taste.
Here is a small comparison list between the two approaches.
| .value | .props |
| ---- | ---|
| ES3 complient | requires ES 5 |
| explicit getter/setter functions: `obj.amount(2)` | object properties with implicit getter/setter: `obj.amount = 2 ` |
| easy to make mistakes; e.g. `obj.amount = 3` instead of `obj.amount(3)`, or `7 * obj.amount` instead of `7 * obj.amount()` wilt both not achieve the intended behavior | Use property reads / assignments |
| easy to observe: `obj.amount.observe(listener)` | `mobservable.observeProperty(obj,'amount',listener)` |
**.value**
* ES3 compliant
* explicit getter/setter functions: `obj.amount(2)`
* easy to make mistakes in assignments; e.g. `obj.amount = 3` instead of `obj.amount(3)`, or `7 * obj.amount` instead of `7 * obj.amount()`
* easy to manually observe: `obj.amount.observe(listener)`
**.props**
* Requires ES5
* object properties with implicit getter/setter: `obj.amount = 2`
* more natural to write / read values, syntactically you won't notice they are observable
* harder to manually observe: `mobservable.observeProperty(obj,'amount',listener)`
## `.reference` versus `.array`
Do *not* confuse `mobservable.primitive([])` (or `mobservable([])`) with `mobservable.array([])`,
the first creates an observable reference to an array, but does not observe its contents.
The later observes the contents from the array you pass into it.
Do *not* confuse `mobservable.reference([])` / `mobservable.primitive([])` with `mobservable([])` / `mobservable.array([])`,
the first two create a observable reference to an array, but does not observe its contents.
The later two observe the content of the array you passed into it, which is probably what you inteded.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc