A Beginners Guide to KnockoutJS: Bindings
Knockout provides a whole set of useful built-in bindings for the most common tasks and scenarios. Each of these bindings allows you to bind simple data values or use JavaScript expressions to calculate the appropriate value. This provides a lot of flexibility and makes it easy to create very dynamic UIs with minimum effort.
The syntax for using the built-in bindings is to include the Knockout binding name and the view model property pairs inside of the data-bind attribute of an HTML element.
// syntax: data-bind="bindingName: bindingProperty" <span data-bind="text: msg"></span>
If you want to data bind to more than one property in the HTML element, simply separate the bindings by a comma using this syntax:
<span data-bind="text: msg, visible: toggle"></span>
You should bear in mind that the most of the bindings attempt to convert any parameter to a boolean value. If you give a value that isn’t actually boolean, it will be interpreted loosely as truthy or falsy. This means that nonzero numbers and non-null objects and non-empty strings will all be interpreted as true, whereas zero, null, undefined, and empty strings will be interpreted as false.
If you understand how to use one type of data binding, then the others should be pretty easy to learn. Now we are going to explain each one of them by providing a description and short example.
Simple Bindings
We’ve already seen text
binding when dealing with observables in the previous tutorial. It sets the text of the associated element to the value of your parameter. This is the equivalent of setting the innerText
(for IE) or textContent
(for other browsers) property of the DOM element. If your parameter is something other than a number or string then the binding will assign the results of toString()
to the element.
If this parameter is an observable value, the binding will update the element’s text whenever the value changes. If the parameter isn’t observable, it will only set the element’s text once and will not update it again later. This is valid for all bindings.
The text
binding is often used to display values in a span
or div
element. When it is used, any previous text will be overwritten.
<p>The tip of the day is: <span data-bind="text: tipOfTheDay"></span></p> function viewModel() { var self = this; self.tipOfTheDay = ko.observable('Relax.Take it easy!') }; ko.applyBindings(new viewModel());
value
binding sets the value of the associated element to the value of your parameter. This is typically used for form elements like input
, select
and textarea
. When the user edits the value in the associated form control, it updates the value on your view model. Likewise, when you update the value in your view model, this updates the value of the form control on screen. This is known as two-way binding. If your parameter is something other than a number or string then the binding will assign the results of toString()
to the element.
By default, Knockout updates your view model when the user transfers focus to another DOM node, on the change
event, but you can control when the value is updated using the valueUpdate
parameter described below. If your binding also includes a parameter called valueUpdate
, this defines which browser event Knockout should use to detect changes.
"change"
is the default event and it updates your view model when the user moves the focus to a different control, or in the case of <select>
elements, immediately after any change.
"afterkeydown"
– updates your view model as soon as the user begins typing a character. This works by catching the browser’s keydown event and handling the event asynchronously. If you want to keep your view model updated in real-time using "afterkeydown"
will be the best choice.
"keyup"
– updates your view model when the user releases a key
"keypress"
– updates your view model when the user has typed a key. This updates repeatedly if the user holds a key down
<input data-bind="value: name, valueUpdate: 'afterkeydown'"></input> <p data-bind="text: name"></p> function viewModel() { var self = this; self.name = ko.observable() }; ko.applyBindings(new viewModel());
Control Mark Up
The html
binding isn’t used as often, but it’s very handy for rendering HTML content in your view model. This binding sets the HTML of the associated element to the value of your parameter and is the equivalent of setting the innerHTML
property on the DOM element. If your parameter is something other than a number or string then the binding will assign the results of toString()
to the element.
Since this binding sets your element’s content using innerHTML
, you should be careful not to use it with untrusted model values, because that might open the possibility of a script injection attack. If you cannot guarantee that the content is safe to display, then you can use the text
binding instead.
<div data-bind="html: markup"></div> function viewModel() { var self = this; self.markup = ko.observable('<p><strong>Knockout</strong> is so <em>cool</em>!</p>') }; ko.applyBindings(new viewModel());
While Knockout has many built-in bindings, you will surely encounter some situations for which none exist. For those, Knockout offers the attr
binding, which allows you to data bind any attribute to a view model property. The parameter should be a JavaScript object where the property names are the attributes and the property values are the value that will be bound to the attribute. This is very useful in many common scenarios, such as binding the href
and title
of the a
element or the src
and alt
of the img
element.
<img data-bind="attr: {src: url, alt: details}" /> function viewModel() { var self = this; self.url = ko.observable(images/logo.png) self.details = ko.observable('This is logo') }; ko.applyBindings(new viewModel());
Add Styling
You can bind styles with Knockout using the css
and the style
built-in bindings.
css
binding sets one or more CSS classes for the associated element. The parameter should be a JavaScript object where the property names correspond to the desired CSS classes and the property values evaluate to true or false indicating whether the class should be applied. You can set multiple CSS classes at once.
<style> .colorize {color: red} </style> <p data-bind="css: { colorize: on }">Text</p> function viewModel() { var self = this; self.on = ko.observable(true) }; ko.applyBindings(new viewModel());
You can use an expression to determine when the class will be applied.
<p data-bind="css: { colorize: on() > 3 }">Text</p>
While it is better to use css classes whenever possible, at times you might want to set a specific style as well. Knockout supports this with its style
built-in binding which sets one or more style values for the associated element. The parameter should be an object whose properties correspond to CSS styles names, and the values correspond to the style values you wish to apply. Typically this parameter value is declared using JSON.
<p data-bind="style: {color: on() > 3 ? 'red' : 'black'}">Text</p> function viewModel() { var self = this; self.on = ko.observable(5) }; ko.applyBindings(new viewModel());
Note: When you have an attribute or CSS class whose name is not legal JavaScript variable name then you should wrap the identifier name in quotes so that it becomes a string literal. And if you want to apply style whose name isn’t a legal JavaScript identifier, you must use the JavaScript name for that style.
//incorrect: <div data-bind="attr: { data-something: someValue }">...</div> <div data-bind="css: { my-class: someValue }">...</div> <div data-bind="style: { font-weight: someValue }">...</div> //correct: <div data-bind="attr: { 'data-something': someValue }">...</div> <div data-bind="css: { 'my-class': someValue }">...</div> <div data-bind="style: { fontWeight: someValue }">...</div>
Handling Events
Knockout supports binding to any event through its event
built-in binding. It adds event handlers for the specified events to the associated DOM element. You can use this to bind to any defined HTML events. Within your event handler you can access the current view model data item, the event object, or even custom parameters passed as part of the event binding. To use event
binding, you pass an object literal containing name value pairs for the event name and the view model method, separated by commas.
<p data-bind="event: { mouseover: hello, mouseout: goodbye }"> Mouse over me! </p> <p data-bind="text: helloEnabled"></p> <p data-bind="text: goodbyeEnabled"></p> function viewModel() { var self = this; self.helloEnabled = ko.observable() self.goodbyeEnabled = ko.observable() self.hello = function() { self.helloEnabled('Hello!'); self.goodbyeEnabled(''); } self.goodbye = function() { self.goodbyeEnabled('Goodbye!'); self.helloEnabled(''); } }; ko.applyBindings(new viewModel());
click
binding, as you may guess, is handling the click event. Because it is the most-used binding for events, it’s simply a shortcut to the event
binding.
<button data-bind="click: writeMSG">Show</button> <p data-bind="text: msg"></p> function viewModel() { var self = this; self.msg = ko.observable() self.writeMSG = function() { self.msg('Hello!') } }; ko.applyBindings(new viewModel());
submit
binding is a shortcut for handling the submit event for the form element. When you use the submit
binding on a form, Knockout will prevent the browser’s default submit action for that form. In other words, the browser will call your handler function but will not submit the form to the server. This is a useful default because when you use the submit
binding, it’s normally because you’re using the form as an interface to your view model, not as a regular HTML form. If you do want to let the form submit like a normal HTML form, just return true from your submit handler.
Instead of using submit on the form, you could use click on the submit button. But using submit binding gives you the benefits of using alternative ways to submit the form, such as pressing the enter key while typing into a text box.
Controling UI
visible
binding sets the visibility of the associated element based on the binding parameter value. The binding attempts to convert any parameter to a boolean value. Knockout’s visible
binding should be bound to a property that evaluates to true or false. This takes priority over any display style you’ve defined using CSS.
<button data-bind="click: show">Show Message</button> <button data-bind="click: hide">Hide Message</button> <p data-bind="visible: msg">Hello, Knockout!</p> function viewModel() { var self = this; self.msg = ko.observable() self.show = function() { self.msg(true) } self.hide = function() { self.msg(false) } }; ko.applyBindings(new viewModel());
enable/disable
binding sets the disabled attribute on the associated element based on the supplied value. This is typically used for form elements like the input
, select
and textarea
. Knockout provides built-in bindings to enable and disable input elements. The enable
binding will enable the input element if the property it’s bound to evaluates to true, and will disable the element if it evaluates to false. The disable
binding does the exact opposite
<input data-bind="value: val, valueUpdate: 'afterkeydown'"> <button data-bind="enable: val">Send</button> function viewModel() { var self = this; self.val = ko.observable() }; ko.applyBindings(new viewModel());
Knockout has a built-in binding named hasfocus
that determines and sets which element has the focus. The hasfocus
binding is handy when you want the focus to be set to a specific element on a form for example search form when visitor open the page
<input data-bind="value: val, hasfocus: on"> <button data-bind="enable: on">Send</button> function viewModel() { var self = this; self.val = ko.observable() self.on = ko.observable(false) }; ko.applyBindings(new viewModel());
Dealing with Checkboxes and Radio Buttons
Checkboxes can be data bound to Knockout’s checked
binding. The checked
binding should be bound to a property or expression that evaluates to true or false. Because the view model properties are defined as observables, the checkbox is updated when the source property changes. Likewise, when a user checks or unchecks the checkbox, the value is updated in the view model property. This binding sets the checked state of radio buttons and checkboxes. For checkboxes, the binding attempts to convert any parameter into a boolean value. For radio buttons, the binding compares the buttons value attribute to the binding parameter.
<p>Let me choose my favorite car: <input type="checkbox" data-bind="checked: car" /></p> <div data-bind="visible: car"> Preferred model: <div><input type="radio" name="modelsGroup" value="ferrari" data-bind="checked: model" /> Ferrari</div> <div><input type="radio" name="modelsGroup" value="lamborghini" data-bind="checked: model" /> Lamborghini</div> <div><input type="radio" name="modelsGroup" value="bugatti" data-bind="checked: model" /> Bugatti</div> </div> function viewModel() { var self = this; self.car = ko.observable(), self.model = ko.observable("lamborghini") // Initially selects Lamborghini }; ko.applyBindings(new viewModel());
Creating Dropdown Lists
Dropdown lists have several important properties to load a list of items, display a value, use a different key value and store the user’s selection. Knockout provides a built-in binding for each of these. options
binding sets the options which will appear in a drop-down list element. The value should be an array. This binding cannot be used with anything other than <select>
elements. For a multi-select list, to set which of the options are selected, or to read which of the options are selected, use the selectedOptions
binding. For a single-select list, you can also read and write the selected option using the value
binding.
The options
binding identifies a list of values to display, usually from an array property on the view model.
<p>Choose your destiny: <select data-bind="options: availableRoles"></select></p> function viewModel() { var self = this; self.availableRoles = ko.observableArray(['an artist', 'an actor', 'an author']) }; ko.applyBindings(new viewModel());
The selectedOptions
binding controls which elements in a multi-select list are currently selected. When the user selects or de-selects an item in the multi-select list, this adds or removes the corresponding value to an array on your view model.
<p>Choose your destiny: <select data-bind="options: availableRoles, selectedOptions: selected" multiple="true"></select></p> function viewModel() { var self = this; self.availableRoles = ko.observableArray(['an artist', 'an actor', 'an author']) self.selected = ko.observableArray(['an author']) }; ko.applyBindings(new viewModel());
Sometimes you want to display one value in the dropdown list but use another value when a user selects an item from the list. Knockout’s built-in optionsText
and optionsValue
bindings help. The optionsText
binding is set to the string name of the property to display in the dropdown list, from the options binding. The optionsValue
binding is set to the string name of the property to bind to for the selected value of the item in the dropdown list. optionsCaption
is useful when you don’t want to have any prticular option selected by default. This parameter set a text such as ‘Select an item…’ on top of the options list and show it when there isn’t any particular item selected.
<p>Locales: <select data-bind="options: locales, selectedOptions: selected, optionsCaption: 'Select your locale...', optionsText: 'country', optionsValue: 'code'"></select></p> <p data-bind="text: selected"></p> function viewModel() { var self = this; self.locales = [ { country: 'USA', code: 'en_US' }, { country: 'Spain', code: 'es_ES' }, { country: 'French', code: 'fr_FR' } ] self.selected = ko.observableArray(); } ko.applyBindings(new viewModel());
And that’s all for this part, stay tuned for the finale, same time next week!