New 1.3 features that can help with unobtrusive bindings

by rniemeyer

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-1.3pre.js"></script>
<div>
   <h2 id="header"></h2>
    <ul id="list" data-bind="foreach: items">
        <li>
            <span data-bind="text: name"></span>
            <a class="remove" href="#">Remove</a>
        </li>
    </ul>
    <a id="add" href="#" data-bind="click: addItem">Add Item</a> 
</div>

CSS

a { font-size: .75em; }

JavaScript

/* There is now a hook that plugins can use to run code each time that ko.applyBindings is called
   --note that applyBindings is called by the template engine as well */
ko.beforeApplyBindings = function(root) {
    console.log("I am doing things each time that applyBindings is called", root);
};

var viewModel = {
    items: ko.observableArray([
        { name: "one"},
        { name: "two"},
        { name: "three"}
    ]),
    addItem: function() {
        this.items.push({
            name: "new"
        });
    },
    removeItem: function(item) {
       this.items.remove(item);   
    }
};

//There is now a way to apply bindings externally without using a data-bind attribute
ko.utils.domData.set(document.getElementById("header"), "bindings", function() { return { text: viewModel.items().length + " items" } });

ko.applyBindings(viewModel);

/* ko.dataFor gives you the overall data that was being bound against this element
   ko.contextFor gives you an object that contains the data ($data) along with some other useful information ($parent, $parents, $root) 
   --useful for unobtrusive event handlers that need the context of an item/viewModel.  Can use live/delegate to make sure that dynamically added items are still handled.
*/
$("#list").delegate(".remove", "click", function() {
    viewModel.removeItem(ko.dataFor(this));  //"this" is the element and ko.dataFor(this) returns the item in this case.
});