Knockout style data-binding for Spine
JavaScript CoffeeScript
Switch branches/tags
Nothing to show
Pull request Compare This branch is 4 commits ahead, 7 commits behind nathanpalmer:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Knockout style data-binding for Spine.

Full sample with bindings in data-bind attributes

<p>First name: <input name="firstName" /></p>
<p>Last name: <input name="lastName" /></p>
<h2>Hello, <span id="fullName"> </span>!</h2>
var PersonCollection = Spine.Model.setup("Person", [ 

    fullName: function() {
        return this.firstName + " " + this.lastName;

var PersonController = Spine.Controller.create({
    bindings: {
        "value input[name=firstName]": "firstName",
        "value input[name=lastName]": "lastName",
        "text #fullName": "fullName"

    init: function() {


var Person = PersonCollection.create({ firstName: "", lastName: "" });
var Controller = PersonController.init({ el: 'body', model: Person });

Full sample with bindings in controller bindings property

<div>You've clicked <span id="clicks">&nbsp;</span> times</div>

<button id="clicker">Click me</button>

<div id="reset">
    That's too many clicks! Please stop before you wear out your fingers.
    <button id="resetter">Reset clicks</button>
var ClickCollection = Spine.Model.setup("Click", [ 

    hasClickedTooManyTimes: function() {
        return this.numberOfClicks >= 3;
    canClick: function() {
        return !this.hasClickedTooManyTimes();

var ClickController = Spine.Controller.create({
    events: {
        "click #clicker": "registerClick",
        "click #resetter": "resetClicks"   

    proxied: [ "registerClick" ],

    bindings: {
        "text #clicks": "numberOfClicks",
        "enable #clicker": "canClick",
        "visible #reset": "hasClickedTooManyTimes"

    init: function() {

    registerClick: function() {
        this.model.updateAttribute("numberOfClicks", this.model.numberOfClicks+1);

    resetClicks: function() {
        this.model.updateAttribute("numberOfClicks", 0)


var Clicker = ClickCollection.create({ numberOfClicks: 0 });
var Controller = ClickController.init({ el: 'body', model:Clicker });

More examples.


Bindings can be in the controller's bindings property or in markup in a data-bind attribute.

The general syntax in markup is:

binding-type: value-expression 

The general syntax in a controller bindings property is:

bindings: {}
	"binding-type jquery-selector": "value-expression"

where binding-type is one of:

binding typeelement type(s)
text td, etc. Model value will go in element's textproperty
value input Model value will be bound to the element's valueproperty.
checked input The checkedproperty of the element will be bound with the model value.
options select The optionchildren of the element will be bound with the model values. This supplies the list of items for the select.
selectedOptions select The selected optionvalue will be bound with the model values.
enabled button, input, etc. The enabledproperty of the element will be bound with the model value.
visible Any The visibleproperty of the element will be bound with the model value.
attr Any The value-expression is a key-value list of attribute-value pairings, e.g. "attr #someEl": '{ "max": "modelMax", "min": "modelMin" }'
hash none -- use hash key in plnace of selector The hash portion of the URL will be bound with the model value.
cookie none -- use cookie key in plnace of selector A value stored in a cookie will be bound with the model value.

The value-expression is usually a model property, but it can also be a function. If you bind to a function then the function will be called with the input (etc.) value as the first argument when the input changes, but with an undefined first argument when the input needs to be updated. Also, if you bind to a function, then you may need to explicitly refresh the bindings in the controller with the refreshBindings method: