custom binding provider (data-class)
by rniemeyer
HTML
<script src="http://jsfiddle.net/rniemeyer/ZnNCG/"></script>
<script src="https://raw.github.com/rniemeyer/rniemeyer.github.com/master/KnockMeOut/Scripts/knockout-1.3ctp.debug.js"></script>
<div id="list">
<h2>Product</h2>
<ul data-class="products">
<li>
<a href="#" data-class="nameText selectLink"></a>
<span class="selected" data-class="nameText selectSpan"></span>
</li>
</ul>
</div>
<div id="editor" style="display: none" data-class="editor">
<div>
Name<br/>
<input data-class="nameVal keydown" />
</div>
<div>
Description<br/>
<input data-class="descVal keydown" />
</div>
<div>
<button data-class="dirty save">Save</button>
<button data-class="dirty cancel">Cancel</button>
<span data-class="saveStatus"></span>
</div>
</div>
CSS
input { margin-bottom: 10px; }
h2 { font-size: 1.25em; font-weight: bold; }
.error { color: red }
.success { color: green }
.selected { color: blue; font-weight: bold; }
#list {
width: 100px;
height: 150px;
border: solid 1px black;
padding: 5px;
float: left;
}
#editor {
height: 150px;
border: solid 1px black;
padding: 5px;
margin-left: 120px;
}
JavaScript
//You can now create a bindingProvider that uses something different than data-bind attributes
ko.customBindingProvider = function(bindingObject) {
this.bindingObject = bindingObject;
//determine if an element has any bindings
this.nodeHasBindings = function(node) {
return node.getAttribute ? node.getAttribute("data-class") : false;
};
//return the bindings given a node and the bindingContext
this.getBindings = function(node, bindingContext) {
var i, j, bindingAccessor, binding,
result = {},
classes = node.getAttribute("data-class");
if (classes) {
classes = classes.split(' ');
//evaluate each class, build a single object to return
for (i = 0, j = classes.length; i < j; i++) {
bindingAccessor = this.bindingObject[classes[i]];
if (bindingAccessor) {
binding = typeof bindingAccessor == "function" ? bindingAccessor.call(bindingContext.$data) : bindingAccessor;
ko.utils.extend(result, binding);
}
}
}
return result;
};
};
/*
This is the definition for an extended observable called a "protectedObservable"
-this would generally belong in a separate library
-the idea is that you can still use it just like any observable, but it has more features
-some of the extra features that it provides
-when someone writes to it, the value is cached until you call its "commit" method
-a "reset" method will update the bound fields back to the original value
-the temporary value is exposed, in case you need to send it to the server
-a dirtyFlag is exposed using a dependentObservable that checks the original vs. temp value
-now you can bind to your observable and any of its sub-observables (temp, isDirty, commit, reset)
-this post explains this idea in more detail:...