Watch.js 1.4.2 Download
⚠ This project is no longer maintained, for more active development, check on-change
Watch.JS is a small library with a lot of possibilities. You may know that the "Observer" design pattern involves executing some function when an observed object changes. Other libraries exist that do this, but with Watch.JS you will not have to change the way you develop. Take a look at the examples to see how simple it is to add Watch.JS to your code.
Works with: IE 9+, FF 4+, SF 5+, WebKit, CH 7+, OP 12+, BESEN, Node.JS , Rhino 1.7+
<scriptsrc="watch.js" type="text/javascript"></script><!-- watch will be a global variable -->npm install melanke-watchjs
importWatchJSfrom'melanke-watchjs';varwatch=WatchJS.watch;varunwatch=WatchJS.unwatch;varcallWatchers=WatchJS.callWatchers;varWatchJS=require("melanke-watchjs")varwatch=WatchJS.watch;varunwatch=WatchJS.unwatch;varcallWatchers=WatchJS.callWatchers;require("watch",function(WatchJS){varwatch=WatchJS.watch;varunwatch=WatchJS.unwatch;varcallWatchers=WatchJS.callWatchers;});//defining our object however we likevarex1={attr1: "initial value of attr1",attr2: "initial value of attr2"};//defining a 'watcher' for an attributewatch(ex1,"attr1",function(){alert("attr1 changed!");});//when changing the attribute its watcher will be invokedex1.attr1="other value";//defining our object however we likevarex2={attr1: 0,attr2: 0,attr3: 0};//defining a 'watcher' for the attributeswatch(ex2,["attr2","attr3"],function(){alert("attr2 or attr3 changed!");});//when changing one of the attributes its watcher will be invokedex2.attr2=50;//defining our object however we likevarex3={attr1: 0,attr2: "initial value of attr2",attr3: ["a",3,null]};//defining a 'watcher' for the objectwatch(ex3,function(){alert("some attribute of ex3 changes!");});//when changing one of the attributes of the object the watcher will be invokedex3.attr3.push("new value");varobj={phrase: "hey",name: "buddy",alert: function(){alert(obj.phrase+" "+obj.name);},alert2: function(){alert(obj.name+", "+obj.phrase);}}watch(obj,"name",obj.alert);watch(obj,"name",obj.alert2);obj.name="johnny";unwatch(obj,"name",obj.alert);obj.name="phil";//defining our object no matter which way we wantvarex1={attr1: "initial value of attr1",attr2: "initial value of attr2"};//defining a 'watcher' for an attributewatch(ex1,"attr1",function(prop,action,newvalue,oldvalue){alert(prop+" - action: "+action+" - new: "+newvalue+", old: "+oldvalue+"... and the context: "+JSON.stringify(this));});//when changing the attribute its watcher will be invokedex1.attr1="other value";If you don't want to call a second watcher in the current scope just set WatchJS.noMore to true and it will be reset to false when this watcher finishes.
//defining our object however we likevarex1={attr1: "inicial value of attr1",attr2: "initial value of attr2"};//defining a 'watcher' for an attributewatch(ex1,"attr1",function(){WatchJS.noMore=true;//prevent invoking watcher in this scopeex1.attr2=ex1.attr1+" + 1";});//defining other 'watcher' for another attributewatch(ex1,"attr2",function(){alert("attr2 changed");});ex1.attr1="other value to 1";//attr1 will be changed but will not invoke the attr2`s watcher//defining our object no matter which way we wantvarex={//level 0l1a: "bla bla",l1b: {//level 1 or lessl2a: "lo lo",l2b: {//level 2 or lessdeeper: "so deep"}}};watch(ex,function(){alert("ex changed at lvl 2 or less");},1);watch(ex,function(){alert("ex changed at lvl 3 or less");},2);ex.l1b.l2b.deeper="other value";ex.l1b.l2b="other value";After declaring a watcher for some object, when you add new attributes to this object and/or change it, the watcher will not be invoked.
//defining our object however we likevarex6={attr1: 0,attr2: 1};//defining a 'watcher' for the objectwatch(ex6,function(){alert("some attribute of ex6 changed!")});ex6.attr3=null;//no watcher will be invokedex6.attr3="value";//no watcher will be invokedWell this is not perfect, you may have to wait 50 miliseconds
//defining our object no matter which way we wantvarex={l1a: "bla bla",l1b: {l2a: "lo lo",l2b: "hey hey"}};watch(ex,function(prop,action,difference,oldvalue){alert("prop: "+prop+"\n action: "+action+"\n difference: "+JSON.stringify(difference)+"\n old: "+JSON.stringify(oldvalue)+"\n ... and the context: "+JSON.stringify(this));},0,true);ex.l1b.l2c="new attr";//it is not instantaneous, you may wait 50 milisecondssetTimeout(function(){ex.l1b.l2c="other value";},100);//defining our object however we likevarex7={attr1: 0,attr2: 1};//defining a 'watcher' for the objectwatch(ex7,function(){alert("some attribute of ex6 changed!")});callWatchers(ex7,"attr1");//invoke the watcher$(function(){varobj={cont: 0};watch(obj,"cont",function(){alert("obj.cont = "+obj.cont);});$("#button").click(function(){obj.cont++;});});//open the browser log to view the messagesvarApple=function(type){var_thisApple=this;this.type=type;this.color="red";this.getInfo=function(){returnthis.color+' '+this.type+' apple';};watch(this,function(){console.log("although we are using Watch.js the apple structure remains the same");for(variin_thisApple){console.log(i+": "+_thisApple[i]);}});};varapple=newApple("macintosh");apple.type="other";varBanana=function(type){var_thisBanana=this;this.type=type;this.color="yellow";watch(this,function(){console.log("although we are using Watch.js the banana structure remains the same");for(variin_thisBanana){console.log(i+": "+_thisBanana[i]);}});};Banana.prototype.getInfo=function(){returnthis.color+' '+this.type+' banana';};varbanana=newBanana("Cavendish");banana.type="other";varorange={type: "pocan",color: "orange",getInfo: function(){returnthis.color+' '+this.type+' apple';}};watch(orange,function(){console.log("although we are using Watch.js the orange structure remains the same");for(variinorange){console.log(i+": "+orange[i]);}});orange.type="other";