<ahref="labs/architecture-examples/rappidjs/"data-source="http://www.rappidjs.com"data-content="rAppid.js is a declarative JavaScript framework for rapid web application development. It supports dependency loading, Model-View binding, View-Model binding, dependency injection and i18n.">rAppid.js</a>
</li>
<liclass="routing labs">
<ahref="labs/architecture-examples/knockoutjs_classBindingProvider/"data-source="https://github.com/rniemeyer/knockout-classBindingProvider"data-content="This project is an adaptation of /architecture-examples/knockoutjs with Ryan Niemeyer's Class Binding Provider.">Knockout +<br> ClassBinding</a>
</li>
<liclass="labs">
<ahref="labs/architecture-examples/extjs_deftjs/"data-source="http://deftjs.org/"data-content="Essential extensions for enterprise web and mobile application development with Ext JS and Sencha Touch">DeftJS + ExtJS</a>
0;j=u[e];e++)if(s.value===j.value){s.moved=j.index;j.moved=s.index;u.splice(e,1);b=e=0;break}b+=e}returng.reverse()}functionS(a,d,c,e,f){varf=f||{},g=a&&M(a),g=g&&g.ownerDocument,h=f.templateEngine||N;b.ya.ub(c,h,g);c=h.renderTemplate(c,e,f,g);("number"!=typeofc.length||0<c.length&&"number"!=typeofc[0].nodeType)&&i(Error("Template engine must return an array of DOM nodes"));g=q;switch(d){case"replaceChildren":b.e.N(a,c);g=l;break;case"replaceNode":b.a.Xa(a,c);g=l;break;case"ignoreTargetNode":break;
e[g];"function"===typeofh?(g=h(a[f].value))&&i(Error(g)):h||i(Error("This template engine does not support the '"+g+"' binding within its templates"))}}a="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+b.g.ba(a)+" } })()})";returnc.createJavaScriptEvaluatorBlock(a)+d}functionW(a,d,c,e){functionf(a){returnfunction(){returnj[a]}}functiong(){returnj}varh=0,j,k;b.j(function(){varm=c&&cinstanceofb.z?c:newb.z(b.a.d(c)),p=m.$data;e&&b.cb(a,m);if(j=("function"==typeofd?
d(m,a):d)||b.J.instance.getBindings(a,m)){if(0===h){h=1;for(varrinj){varu=b.c[r];u&&8===a.nodeType&&!b.e.I[r]&&i(Error("The binding '"+r+"' cannot be used with virtual elements"));if(u&&"function"==typeofu.init&&(u=(0,u.init)(a,f(r),g,p,m))&&u.controlsDescendantBindings)k!==H&&i(Error("Multiple bindings ("+k+" and "+r+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.")),k=r}h=2}if(2===h)for(rinj)(u=b.c[r])&&"function"==
typeofu.update&&(0,u.update)(a,f(r),g,p,m)}},n,{W:a});return{Mb:k===H}}functionX(a,d,c){vare=l,f=1===d.nodeType;f&&b.e.Sa(d);if(f&&c||b.J.instance.nodeHasBindings(d))e=W(d,n,a,c).Mb;e&&Y(a,d,!f)}functionY(a,d,c){for(vare=b.e.firstChild(d);d=e;)e=b.e.nextSibling(d),X(a,d,c)}functionZ(a,b){varc=$(a,b);returnc?0<c.length?c[c.length-1].nextSibling:a.nextSibling:n}function$(a,b){for(varc=a,e=1,f=[];c=c.nextSibling;){if(G(c)&&(e--,0===e))returnf;f.push(c);y(c)&&e++}b||i(Error("Cannot find closing comment tag to match: "+
d,function(a){c.call(b,a)}):i(Error("Browser doesn't support addEventListener or attachEvent"))},Aa:function(b,d){(!b||!b.nodeType)&&i(Error("element must be a DOM node when calling triggerEvent"));if("undefined"!=typeofE){varc=[];a(b,d)&&c.push({mb:b.checked});E(b).trigger(d,c)}else"function"==typeofx.createEvent?"function"==typeofb.dispatchEvent?(c=x.createEvent(e[d]||"HTMLEvents"),c.initEvent(d,l,l,w,0,0,0,0,0,q,q,q,q,0,b),b.dispatchEvent(c)):i(Error("The supplied element doesn't support dispatchEvent")):
"undefined"!=typeofb.fireEvent?(a(b,d)&&(b.checked=b.checked!==l),b.fireEvent("on"+d)):i(Error("Browser doesn't support triggering events"))},d:function(a){returnb.$(a)?a():a},ta:function(a){returnb.$(a)?a.t():a},da:function(a,d,c){if(d){vare=/[\w-]+/g,f=a.className.match(e)||[];b.a.o(d.match(e),function(a){vard=b.a.i(f,a);0<=d?c||f.splice(d,1):c&&f.push(a)});a.className=f.join("")}},bb:function(a,d){varc=b.a.d(d);if(c===n||c===H)c="";vare=b.e.firstChild(a);!e||3!=e.nodeType||b.e.nextSibling(e)?
m,Pb:7===m,Z:m,Na:function(a,d){for(varc=b.a.L(a.getElementsByTagName("input")).concat(b.a.L(a.getElementsByTagName("textarea"))),e="string"==typeofd?function(a){returna.name===d}:function(a){returnd.test(a.name)},f=[],g=c.length-1;0<=g;g--)e(c[g])&&f.push(c[g]);returnf},Hb:function(a){return"string"==typeofa&&(a=b.a.D(a))?w.JSON&&w.JSON.parse?w.JSON.parse(a):(newFunction("return "+a))():n},wa:function(a,d,c){("undefined"==typeofJSON||"undefined"==typeofJSON.stringify)&&i(Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js"));
c);e===H&&d&&(e=[],b.a.f.set(a,c,e));returne}functiond(c){vare=a(c,q);if(e)for(vare=e.slice(0),j=0;j<e.length;j++)e[j](c);b.a.f.clear(c);"function"==typeofE&&"function"==typeofE.cleanData&&E.cleanData([c]);if(f[c.nodeType])for(e=c.firstChild;c=e;)e=c.nextSibling,8===c.nodeType&&d(c)}varc="__ko_domNodeDisposal__"+(newDate).getTime(),e={1:l,8:l,9:l},f={1:l,9:l};return{Ba:function(b,d){"function"!=typeofd&&i(Error("Callback must be a function"));a(b,l).push(d)},Wa:function(d,e){varf=a(d,q);
a+c[2]+"</div>";for("function"==typeofw.innerShiv?d.appendChild(w.innerShiv(a)):d.innerHTML=a;c[0]--;)d=d.lastChild;d=b.a.L(d.lastChild.childNodes)}returnd};b.a.ca=function(a,d){b.a.ka(a);d=b.a.d(d);if(d!==n&&d!==H)if("string"!=typeofd&&(d=d.toString()),"undefined"!=typeofE)E(a).html(d);elsefor(varc=b.a.sa(d),e=0;e<c.length;e++)a.appendChild(c[e])};b.b("utils.parseHtmlFragment",b.a.sa);b.b("utils.setHtml",b.a.ca);varQ={};b.s={qa:function(a){"function"!=typeofa&&i(Error("You can only pass a function to ko.memoization.memoize()"));
varb=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);Q[b]=a;return"<\!--[ko_memo:"+b+"]--\>"},gb:function(a,b){varc=Q[a];c===H&&i(Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized."));try{returnc.apply(n,b||[]),l}finally{deleteQ[a]}},hb:function(a,d){varc=[];ba(a,c);for(vare=0,f=c.length;e<f;e++){varg=c[e].rb,h=[g];d&&b.a.P(h,d);b.s.gb(c[e].Eb,h);g.nodeValue="";g.parentNode&&g.parentNode.removeChild(g)}},
end:function(){B.pop()},Va:function(a){b.Pa(a)||i(Error("Only subscribable things can act as dependencies"));if(0<B.length){vard=B[B.length-1];d&&!(0<=b.a.i(d.Ka,a))&&(d.Ka.push(a),d.ha(a))}},K:function(a,b,c){try{returnB.push(n),a.apply(b,c||[])}finally{B.pop()}}};varla={undefined:l,"boolean":l,number:l,string:l};b.m=function(a){functiond(){if(0<arguments.length){if(!d.equalityComparer||!d.equalityComparer(c,arguments[0]))d.H(),c=arguments[0],d.G();returnthis}b.r.Va(d);returnc}varc=a;b.S.call(d);
a[D]===b.m||"function"==typeofa&&a[D]===b.j&&a.yb?l:q};b.b("observable",b.m);b.b("isObservable",b.$);b.b("isWriteableObservable",b.Qa);b.R=function(a){0==arguments.length&&(a=[]);a!==n&&(a!==H&&!("length"ina))&&i(Error("The argument passed when initializing an observable array must be an array, or null, or undefined."));vard=b.m(a);b.a.extend(d,b.R.fn);returnd};b.R.fn={remove:function(a){for(varb=this.t(),c=[],e="function"==typeofa?a:function(b){returnb===a},f=0;f<b.length;f++){varg=b[f];
i(Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.")),this;m||g();b.r.Va(h);returnk}functionj(){return!m||0<z.length}vark,m=q,p=q,r=a;r&&"object"==typeofr?(c=r,r=c.read):(c=c||{},r||(r=c.read));"function"!=typeofr&&i(Error("Pass a function that returns the value of the ko.computed"));varu=c.write,F=c.disposeWhenNodeIsRemoved||c.W||n,v=c.disposeWhen||c.Ja||t(q),A=e,z=[],s=n;d||(d=c.owner);h.t=function(){m||
b.b("computed",b.j);b.b("isComputed",b.Ab);b.fb=function(a){0==arguments.length&&i(Error("When calling ko.toJS, pass the object you want to convert."));returnaa(a,function(a){for(varc=0;b.$(a)&&10>c;c++)a=a();returna})};b.toJSON=function(a,d,c){a=b.fb(a);returnb.a.wa(a,d,c)};b.b("toJS",b.fb);b.b("toJSON",b.toJSON);b.k={q:function(a){switch(b.a.u(a)){case"option":returna.__ko__hasDomDataOptionValue__===l?b.a.f.get(a,b.c.options.ra):7>=b.a.Z?a.getAttributeNode("value").specified?a.value:a.text:
"__ko_bindingContext__")};b.Ea=function(a,d,c){1===a.nodeType&&b.e.Sa(a);returnW(a,d,c,l)};b.Da=function(a,b){(1===b.nodeType||8===b.nodeType)&&Y(a,b,l)};b.Ca=function(a,b){b&&(1!==b.nodeType&&8!==b.nodeType)&&i(Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"));b=b||w.document.body;X(a,b,l)};b.ja=function(a){switch(a.nodeType){case1:case8:vard=b.cb(a);if(d)returnd;if(a.parentNode)returnb.ja(a.parentNode)}returnH};b.ob=function(a){return(a=
b.c.options={update:function(a,d,c){"select"!==b.a.u(a)&&i(Error("options binding applies only to SELECT elements"));for(vare=0==a.length,f=b.a.V(b.a.fa(a.childNodes,function(a){returna.tagName&&"option"===b.a.u(a)&&a.selected}),function(a){returnb.k.q(a)||a.innerText||a.textContent}),g=a.scrollTop,h=b.a.d(d());0<a.length;)b.A(a.options[0]),a.remove(0);if(h){varc=c(),j=c.optionsIncludeDestroyed;"number"!=typeofh.length&&(h=[h]);if(c.optionsCaption){vark=x.createElement("option");b.a.ca(k,c.optionsCaption);
b.c.selectedOptions={init:function(a,d,c){b.a.n(a,"change",function(){vare=d(),f=[];b.a.o(a.getElementsByTagName("option"),function(a){a.selected&&f.push(b.k.q(a))});b.g.ea(e,c,"value",f)})},update:function(a,d){"select"!=b.a.u(a)&&i(Error("values binding applies only to SELECT elements"));varc=b.a.d(d());c&&"number"==typeofc.length&&b.a.o(a.getElementsByTagName("option"),function(a){vard=0<=b.a.i(c,b.k.q(a));b.a.ab(a,d)})}};b.c.style={update:function(a,d){varc=b.a.d(d()||{}),e;for(einc)if("string"==
typeofe){varf=b.a.d(c[e]);a.style[e]=f||""}}};b.c.submit={init:function(a,d,c,e){"function"!=typeofd()&&i(Error("The value for a submit binding must be a function"));b.a.n(a,"submit",function(b){varc,h=d();try{c=h.call(e,a)}finally{c!==l&&(b.preventDefault?b.preventDefault():b.returnValue=q)}})}};b.c.text={update:function(a,d){b.a.bb(a,d())}};b.e.I.text=l;b.c.uniqueName={init:function(a,d){if(d()){varc="ko_unique_"+++b.c.uniqueName.nb;b.a.$a(a,c)}}};b.c.uniqueName.nb=0;b.c.value={init:function(a,
d,c){d.isTemplateRewritten(a,c)||d.rewriteTemplate(a,function(a){returnb.ya.Fb(a,d)},c)},Fb:function(a,b){returna.replace(pa,function(a,e,f,g,h,j,k){returnV(k,e,b)}).replace(qa,function(a,e){returnV(e,"<\!-- ko --\>",b)})},jb:function(a){returnb.s.qa(function(d,c){d.nextSibling&&b.Ea(d.nextSibling,a,c)})}};b.b("__tr_ambtns",b.ya.jb);b.l={};b.l.h=function(a){this.h=a};b.l.h.prototype.text=function(){vara=b.a.u(this.h),a="script"===a?"text":"textarea"===a?"value":"innerHTML";if(0==arguments.length)returnthis.h[a];
function(){if(0==arguments.length)return(b.a.f.get(this.h,"__ko_anon_template__")||{}).ia;b.a.f.set(this.h,"__ko_anon_template__",{ia:arguments[0]})};b.b("templateSources",b.l);b.b("templateSources.domElement",b.l.h);b.b("templateSources.anonymousTemplate",b.l.O);varN;b.va=function(a){a!=H&&!(ainstanceofb.v)&&i(Error("templateEngine must inherit from ko.templateEngine"));N=a};b.ua=function(a,d,c,e,f){c=c||{};(c.templateEngine||N)==H&&i(Error("Set a template engine before calling renderTemplate"));
b.g.Db(a,"name")?n:"This template engine does not support anonymous templates nested within its templates"};b.e.I.template=l;b.b("setTemplateEngine",b.va);b.b("renderTemplate",b.ua);b.a.Ia=function(a,b,c){a=a||[];b=b||[];returna.length<=b.length?R(a,b,"added","deleted",c):R(b,a,"deleted","added",c)};b.b("utils.compareArrays",b.a.Ia);b.a.Za=function(a,d,c,e,f){functiong(a,b){s=k[b];v!==b&&(A[a]=s);s.ma(v++);L(s.M);r.push(s);y.push(s)}functionh(a,c){if(a)for(vard=0,e=c.length;d<e;d++)c[d]&&b.a.o(c[d].M,
q};b.C.prototype=newb.v;b.C.prototype.renderTemplateSource=function(a){vard=!(9>b.a.Z)&&a.nodes?a.nodes():n;if(d)returnb.a.L(d.cloneNode(l).childNodes);a=a.text();returnb.a.sa(a)};b.C.na=newb.C;b.va(b.C.na);b.b("nativeTemplateEngine",b.C);b.pa=function(){vara=this.Cb=function(){if("undefined"==typeofE||!E.tmpl)return0;try{if(0<=E.tmpl.tag.tmpl.open.toString().indexOf("__"))return2}catch(a){}return1}();this.renderTemplateSource=function(b,c,e){e=e||{};2>a&&i(Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later."));
# Knockout.js with the Class Binding Provider TodoMVC Example
The Class Binding Provider offers advanced KnockoutJS developers a modular and reusable way to write their bindings. It works similarly to css classes providing you with a way to declare your bindings in JavaScript and then reference them using keys in your HTML.
To learn how to implement the Class Binding Provider, [read the documentation](https://github.com/rniemeyer/knockout-classBindingProvider).
**What are the benefits of this approach to Knockout bindings?**
* The markup can stay clean and simple
* Bindings can be re-used, even at different scopes
* You can set breakpoints in the bindings to inspect the data being passed through them
* You can do logging in the bindings to understanding how many times they are being called
* You can change/alter the bindings on an element whenever your bindings are triggered
* Bindings go through less parsing (do not need to go from a object literal in a string to code)
## Learning Knockout.js
The [Knockout.js website](http://knockoutjs.com) is a great resource for getting started.
*[Getting Started with Knockout.js](http://www.adobe.com/devnet/html5/articles/getting-started-with-knockoutjs.html)
*[Into the Ring with Knockout.js](http://net.tutsplus.com/tutorials/javascript-ajax/into-the-ring-with-knockout-js)
*[Beginners Guide to Knockout.js](http://www.sitepoint.com/beginners-guide-to-knockoutjs-part-1)
Get help from other Knockout.js users:
*[Knockout.js on StackOverflow](http://stackoverflow.com/questions/tagged/knockout)
*[Mailing list on Google Groups](http://groups.google.com/group/knockoutjs)
*[Knockout.js on Twitter](http://twitter.com/knockoutjs)
*[Knockout.js on Google +](https://plus.google.com/communities/106789046312204355684/stream/c5bfcfdf-3690-44a6-b015-35aad4f4e42e)
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
## Credit
[ashish101](https://github.com/ashish01/knockoutjs-todos) wrote the original version of this application, which was then refactored by Addy Osmani and later rewritten by TodoMVC contributors.
[mberkom](https://github.com/mberkom) rewrote the binding references to use Ryan Niemeyer's Class Binding Provider instead of Knockout's default `data-bind` method of binding.