Knockout style data-binding for Spine.
<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", [
"firstName",
"lastName"
]);
PersonCollection.include({
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() {
this.initializeBindings(this.model);
}
});
PersonController.include(DataBind);
var Person = PersonCollection.create({ firstName: "", lastName: "" });
var Controller = PersonController.init({ el: 'body', model: Person });
<div>You've clicked <span id="clicks"> </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>
</div>
var ClickCollection = Spine.Model.setup("Click", [
"numberOfClicks"
]);
ClickCollection.include({
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() {
this.initializeBindings(this.model);
},
registerClick: function() {
this.model.updateAttribute("numberOfClicks", this.model.numberOfClicks+1);
},
resetClicks: function() {
this.model.updateAttribute("numberOfClicks", 0)
}
});
ClickController.include(Spine.DataBind);
var Clicker = ClickCollection.create({ numberOfClicks: 0 });
var Controller = ClickController.init({ el: 'body', model:Clicker });
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 type | element type(s) | |
---|---|---|
text | td , etc. |
Model value will go in element's text property |
value | input |
Model value will be bound to the element's value property. |
checked | input |
The checked property of the element will be bound with the model value. |
options | select |
The option children of the element will be bound with the model values. This supplies the list of items for the select. |
selectedOptions | select |
The selected option value will be bound with the model values. |
enabled | button , input , etc. |
The enabled property of the element will be bound with the model value. |
visible | Any | The visible property 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:
this.refreshBindings(this.model);