Excerpt From Writing Modular JavaScript With AMD, CommonJs & ES Harmony:
When we say an application is modular, we generally mean it's composed of a set of highly decoupled, distinct pieces of functionality stored in modules. As you probably know, loose coupling facilitates easier maintainability of apps by removing dependencies where possible. When this is implemented efficiently, its quite easy to see how changes to one part of a system may affect another.
Unlike some more traditional programming languages however, the current iteration of JavaScript (ECMA-262) doesn't provide developers with the means to import such modules of code in a clean, organized manner. It's one of the concerns with specifications that haven't required great thought until more recent years where the need for more organized JavaScript applications became apparent.
Instead, developers at present are left to fall back on variations of the module or object literal patterns. With many of these, module scripts are strung together in the DOM with namespaces being described by a single global object where it's still possible to incur naming collisions in your architecture. There's also no clean way to handle dependency management without some manual effort or third party tools.
Whilst native solutions to these problems will be arriving in ES Harmony, the good news is that writing modular JavaScript has never been easier and you can start doing it today.
<html>
<head>
<script type="text/javascript" data-main="scripts/init.js" src="scripts/require.js"></script>
</head>
<body>
<p>First name: <input data-bind="value: firstName" /></p>
<p>First name capitalized: <strong data-bind="text: firstNameCaps"></strong></p>
</body>
</html>
require(['knockout-x.y.z', 'appViewModel', 'domReady!'],
function(ko, appViewModel) {
ko.applyBindings(new appViewModel());
});
// Main viewmodel class
define(['knockout-x.y.z'], function(ko) {
return function appViewModel() {
this.firstName = ko.observable('Bert');
this.firstNameCaps = ko.computed(function() {
return this.firstName().toUpperCase();
}, this);
};
});
Of course, x.y.z should be replaced with the version number of the Knockout script you are loading (e.g., knockout-3.1.0).
Documentation on Binding Handlers in general can be found here. This section is meant to demonstrate the power that AMD modules provide in maintaining your custom handlers. We will take the example of the ko.bindingHandlers.hasFocus example from the binding handlers documentation. By wrapping that handler in it's own module you can restrict it's use only to the pages that need it. The wrapped module becomes:
define(['knockout-x.y.z'], function(ko){
ko.bindingHandlers.hasFocus = {
init: function(element, valueAccessor) { /* ... */ },
update: function(element, valueAccessor) { /* ... */ }
}
});
After you have defined the module update the input element from the HTML example above to be:
<p>First name:
<input data-bind="value: firstName, hasFocus: editingName" />
<span data-bind="visible: editingName">
You're editing the name!
</span>
</p>
Include the module in the list of dependencies for your view model:
define(['knockout-x.y.z', 'customBindingHandlers/hasFocus'], function(ko) {
return function appViewModel(){
/* ... */
// Add an editingName observable
this.editingName = ko.observable();
};
});
Note that the custom binding handler module does not inject anything into our ViewModel module, that is because it does not return anything. It just appends additional behavior to the knockout module.
RequireJs can be downloaded from http://requirejs.org/docs/download.html.
This example shows two ways to animate transitions:
When using the template/foreach binding, you can provide afterAdd and beforeRemove callbacks. These let you intercept the code that actually adds or removes elements, so you can trivially use something like jQuery's slideUp/slideDown() animation methods or similar. To see this in action, switch between different planet types, or add new planets.
It's not hard to write a custom Knockout binding that manipulates element states in arbitrary ways according to the value of an observable. Check the HTML source code to see a custom binding called fadeVisible that, whenever an observable value changes, uses jQuery's fadeIn/fadeOut functions to animate the associated DOM element. To see this in action, check and uncheck the "advanced options" checkbox.
| Identity | Purpose | Source |
|---|---|---|
{{ name }}
|
{{ purpose }} | {{ type }} at {{ source }}:{{ line }} |
Since Knockout 3.0
there has been an arrayChange event that can be attached to an observable
or observableArray.
One subscribes to changes as follows:
obsArray.subscribe(fn, thisArg, "arrayChange");
The main advantages of subscribing to changes:
Performance is O(1) in most cases, i.e., there’s basically no performance implication at all, because for straightforward operations, (push, splice, etc.) KO supplies the change log without running any diff algorithm. KO now only falls back on the diff algorithm if you’ve made an arbitrary change without using a typical array mutation function.
The change log is filtered down just to give you the items that actually changed.
The observableArray has array tracking enabled at construction, but
you can extend any other subscribable (i.e. ko.observable and ko.computed) by extending it as follows:
trackable = ko.observable().extend({trackArrayChanges: true});
The attr binding provides a generic way to set the value of any attribute for the associated DOM element. This is useful, for example, when you need to set the title attribute of an element, the src of an img tag, or the href of a link based on values in your view model, with the attribute value being updated automatically whenever the corresponding model property changes.
This will set the element's href attribute to year-end.html and the element's title attribute to Report including final year-end statistics.
Main parameter
You should pass a JavaScript object in which the property names correspond to attribute names, and the values correspond to the attribute values you wish to apply.
If your parameter references an observable value, the binding will update the attribute whenever the observable value changes. If the parameter doesn't reference an observable value, it will only set the attribute once and will not update it later.
Additional parameters
If you want to apply the attribute data-something, you can't write this:
<div data-bind="attr: { data-something: someValue }">...</div>
... because data-something isn't a legal identifier name at that point. The solution is simple: just wrap the identifier name in quotes so that it becomes a string literal, which is legal in a JavaScript object literal. For example,
<div data-bind="attr: { 'data-something': someValue }">...</div>
A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko.applyBindings(viewModel). Then, each time you use a control flow binding such as with or foreach, that creates a child binding context that refers to the nested view model data.
Bindings contexts offer the following special properties that you can reference in any binding:
$parent
This is the view model object in the parent context, the one immeditely outside the current context. In the root context, this is undefined. Example:
<h1 data-bind="text: name"></h1>
<div data-bind="with: manager">
<!-- Now we're inside a nested binding context -->
<span data-bind="text: name"></span> is the
manager of <span data-bind="text: $parent.name"></span>
</div>
$parents
This is an array representing all of the parent view models:
$parents[0] is the view model from the parent context (i.e., it's the same as $parent)
$parents[1] is the view model from the grandparent context
$parents[2] is the view model from the great-grandparent context
... and so on.
$root
This is the main view model object in the root context, i.e., the topmost parent context. It's usually the object that was passed to ko.applyBindings. It is equivalent to $parents[$parents.length - 1].
$data
This is the view model object in the current context. In the root context, $data and $root are equivalent. Inside a nested binding context, this parameter will be set to the current data item (e.g., inside a with: person binding, $data will be set to person). $data is useful when you want to reference the viewmodel itself, rather than a property on the viewmodel. Example:
<ul data-bind="foreach: ['cats', 'dogs', 'fish']">
<li>The value is <span data-bind="text: $data"></span></li>
</ul>
$index (only available within foreach bindings)
This is the zero-based index of the current array entry being rendered by a foreach binding. Unlike the other binding context properties, $index is an observable and is updated whenever the index of the item changes (e.g., if items are added to or removed from the array).
$parentContext
This refers to the binding context object at the parent level. This is different from $parent, which refers to the data (not binding context) at the parent level. This is useful, for example, if you need to access the index value of an outer foreach item from an inner context (usage: $parentContext.$index). This is undefined in the root context.
$rawData
This is the raw view model value in the current context. Usually this will be the same as $data, but if the view model provided to Knockout is wrapped in an observable, $data will be the unwrapped view model, and $rawData will be the observable itself.
The following special variables are also available in bindings, but are not part of the binding context object:
$context
This refers to the current binding context object. This may be useful if you want to access properties of the context when they might also exist in the view model, or if you want to pass the context object to a helper function in your view model.
$element
This is the element DOM object (for virtual elements, it will be the comment DOM object) of the current binding. This can be useful if a binding needs to access an attribute of the current element. Example:
<div id="item1" data-bind="text: $element.id"></div>
Just like the built-in bindings with and foreach, custom bindings can change the binding context for their descendant elements, or provide special properties by extending the binding context object. This is described in detail under creating custom bindings that control descendant bindings.
Note: Extending the binding syntax using preprocessing is an advanced technique, typically used only when creating libraries of reusable bindings or extended syntaxes. It's not something you'll normally need to do when building applications with Knockout.
Starting with Knockout 3.0, developers can define custom syntaxes by providing callbacks that rewrite DOM nodes and binding strings during the binding process.
You can hook into Knockout's logic for interpreting data-bind attributes by providing a binding preprocessor for a specific binding handler (such as click, visible, or any custom binding handler).
To do this, attach a preprocess function to the binding handler:
ko.bindingHandlers.yourBindingHandler.preprocess = function(stringFromMarkup) {
// Return stringFromMarkup if you don't want to change anything, or return
// some other string if you want Knockout to behave as if that was the
// syntax provided in the original HTML
}
See later on this page for an API reference.
If you leave off the value of a binding, it's bound to undefined by default. If you want to have a different default value for a binding, you can do so with a preprocessor. For example, you can allow uniqueName to be bound without a value by making its default value true:
ko.bindingHandlers.uniqueName.preprocess = function(val) {
return val || 'true';
}
Now you can bind it like this:
<input data-bind="value: someModelProperty, uniqueName" />
If you'd like to be able to bind expressions to click events (rather than a function reference as Knockout expects), you can set up a preprocessor for the click handler to support this syntax:
ko.bindingHandlers.click.preprocess = function(val) {
return 'function($data,$event){ ' + val + ' }';
}
Now you can bind click like this:
<button type="button" data-bind="click: myCount(myCount()+1)">Increment</button>
ko.bindingHandlers.<name>.preprocess(value, name, addBindingCallback)
If defined, this function will be called for each <name> binding before the binding is evaluated.
Parameters:
value: the syntax associated with the binding value before Knockout attempts to parse it (e.g., for yourBinding: 1 + 1, the associated value is "1 + 1" as a string).
name: the name of the binding (e.g., for yourBinding: 1 + 1, the name is "yourBinding" as a string).
addBinding: a callback function you can optionally use to insert another binding on the current element. This requires two parameters, name and value. For example, inside your preprocess function, call addBinding('visible', 'acceptsTerms()'); to make Knockout behave as if the element had a visible: acceptsTerms() binding on it.
Return value:
Your preprocess function must return the new string value to be parsed and passed to the binding, or return undefined to remove the binding.
For example, if you return 'value + ".toUpperCase()"' as a string, then yourBinding: "Bert" would be interpreted as if the markup contained yourBinding: "Bert".toUpperCase(). Knockout will parse the returned value in the normal way, so it has to be a legal JavaScript expression.
Don't return non-string values. That wouldn't make sense, because markup is always a string.
You can hook into Knockout's logic for traversing the DOM by providing a node preprocessor. This is a function that Knockout will call once for each DOM node that it walks over, both when the UI is first bound, and later when any new DOM subtrees are injected (e.g., via a foreach binding).
To do this, define a preprocessNode function on your binding provider:
ko.bindingProvider.instance.preprocessNode = function(node) {
// Use DOM APIs such as setAttribute to modify 'node' if you wish.
// If you want to leave 'node' in the DOM, return null or have no 'return' statement.
// If you want to replace 'node' with some other set of nodes,
// - Use DOM APIs such as insertChild to inject the new nodes
// immediately before 'node'
// - Use DOM APIs such as removeChild to remove 'node' if required
// - Return an array of any new nodes that you've just inserted
// so that Knockout can apply any bindings to them
}
See later on this page for an API reference.
If you commonly include template content using virtual elements, the normal syntax can feel a bit verbose. Using preprocessing, you can add a new template format that uses a single comment:
ko.bindingProvider.instance.preprocessNode = function(node) {
// Only react if this is a comment node of the form <!-- template: ... -->
if (node.nodeType == 8) {
var match = node.nodeValue.match(/^\s*(template\s*:[\s\S]+)/);
if (match) {
// Create a pair of comments to replace the single comment
var c1 = document.createComment("ko " + match[1]),
c2 = document.createComment("/ko");
node.parentNode.insertBefore(c1, node);
node.parentNode.replaceChild(c2, node);
// Tell Knockout about the new nodes so that it can apply bindings to them
return [c1, c2];
}
}
}
Now you can include a template in your view like this:
<!-- template: 'some-template' -->
ko.bindingProvider.instance.preprocessNode(node)
If defined, this function will be called for each DOM node before bindings are processed. The function can modify, remove, or replace node. Any new nodes must be inserted immediately before node, and if any nodes were added or node was removed, the function must return an array of the new nodes that are now in the document in place of node.
Knockout's declarative binding system provides a concise and powerful way to link data to the UI. It's generally easy and obvious to bind to simple data properties or to use a single binding. For more complex bindings, it helps to better understand the behavior and syntax of Knockout's binding system.
A binding consists of two items, the binding name and value, separated by a colon. Here is an example of a single, simple binding:
Today's message is: <span data-bind="text: myMessage"></span>
An element can include multiple bindings (related or unrelated), with each binding separated by a comma. Here are some examples:
<!-- related bindings: valueUpdate is a parameter for value -->
Your value: <input data-bind="value: someValue, valueUpdate: 'afterkeydown'" />
<!-- unrelated bindings -->
Cellphone: <input data-bind="value: cellphoneNumber, enable: hasCellphone" />
The binding name should generally match a registered binding handler (either built-in or custom) or be a parameter for another binding. If the name matches neither of those, Knockout will ignore it (without any error or warning). So if a binding doesn't appear to work, first check that the name is correct.
The binding value can be a single value, variable, or literal or almost any valid JavaScript expression. Here are examples of various binding values:
<!-- variable (usually a property of the current view model -->
<div data-bind="visible: shouldShowMessage">...</div>
<!-- comparison and conditional -->
The item is <span data-bind="text: price() > 50 ? 'expensive' : 'cheap'"></span>.
<!-- function call and comparison -->
<button data-bind="enable: parseAreaCode(cellphoneNumber()) != '555'">...</button>
<!-- function expression -->
<div data-bind="click: function (data) { myFunction('param1', data) }">...</div>
<!-- object literal (with unquoted and quoted property names) -->
<div data-bind="with: {emotion: 'happy', 'facial-expression': 'smile'}">...</div>
These examples show that the value can be just about any JavaScript expression. Even the comma is fine when it's enclosed in braces, brackets, or parentheses. When the value is an object literal, the object's property names must be valid JavaScript identifiers or be enclosed in quotes. If the binding value is an invalid expression or references an unknown variable, Knockout will output an error and stop processing bindings.
Bindings can include any amount of whitespace (spaces, tab, and newlines), so you're free to use it to arrange your bindings as you like. The following examples are all equivalent:
<!-- no spaces -->
<select data-bind="options:availableCountries,optionsText:'countryName',value:selectedCountry,optionsCaption:'Choose...'"></select>
<!-- some spaces -->
<select data-bind="options : availableCountries, optionsText : 'countryName', value : selectedCountry, optionsCaption : 'Choose...'"></select>
<!-- spaces and newlines -->
<select data-bind="
options: availableCountries,
optionsText: 'countryName',
value: selectedCountry,
optionsCaption: 'Choose...'"></select>
Starting with Knockout 3.0, you can specify bindings without a value, which will give the binding an undefined value. For example:
<span data-bind="text">Text that will be cleared when bindings are applied.</span>
This ability is especially useful when paired with binding preprocessing, which can assign a default value for a binding.
Let us know if you think we are missing something!
Knockout is tested on the following browsers:
It's very likely that Knockout also works on older and newer versions of these browsers, but there's only so many combinations we can check regularly! At the time of the last check, Knockout was also found to work on the following browsers (though we don't recheck these for every release):
To get a good idea of how Knockout will run on another browser or platform, simply run the test suite. This will validate hundreds of behavioral specifications and produce a report of any problems. The pass rate should be 100% on all the browsers listed above.
The checked binding links a checkable form control — i.e., a checkbox (<input type='checkbox'>) or a radio button (<input type='radio'>) — with a property on your view model.
When the user checks the associated form control, this updates the value on your view model. Likewise, when you update the value in your view model, this checks or unchecks the form control on screen.
Note: For text boxes, drop-down lists, and all non-checkable form controls, use the value binding to read and write the element's value, not the checked binding.
<p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p>
var viewModel = {
wantsSpam: ko.observable(true) // Initially checked
};
// ... then later ...
viewModel.wantsSpam(false); // The checkbox becomes unchecked
<p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p>
<div data-bind="visible: wantsSpam">
Preferred flavors of spam:
<div><input type="checkbox" value="cherry" data-bind="checked: spamFlavors" /> Cherry</div>
<div><input type="checkbox" value="almond" data-bind="checked: spamFlavors" /> Almond</div>
<div><input type="checkbox" value="msg" data-bind="checked: spamFlavors" /> Monosodium Glutamate</div>
</div>
var viewModel = {
wantsSpam: ko.observable(true),
spamFlavors: ko.observableArray(["cherry","almond"]) // Initially checks the Cherry and Almond checkboxes
};
// ... then later ...
viewModel.spamFlavors.push("msg"); // Now additionally checks the Monosodium Glutamate checkbox
<p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p>
<div data-bind="visible: wantsSpam">
Preferred flavor of spam:
<div><input type="radio" name="flavorGroup" value="cherry" data-bind="checked: spamFlavor" /> Cherry</div>
<div><input type="radio" name="flavorGroup" value="almond" data-bind="checked: spamFlavor" /> Almond</div>
<div><input type="radio" name="flavorGroup" value="msg" data-bind="checked: spamFlavor" /> Monosodium Glutamate</div>
</div>
var viewModel = {
wantsSpam: ko.observable(true),
spamFlavor: ko.observable("almond") // Initially selects only the Almond radio button
};
// ... then later ...
viewModel.spamFlavor("msg"); // Now only Monosodium Glutamate is checked
Main parameter
KO sets the element's checked state to match your parameter value. Any previous checked state will be overwritten. The way your parameter is interpreted depends on what type of element you're binding to:
For checkboxes, KO will set the element to be checked when the parameter value is true, and unchecked when it is false. If you give a value that isn't actually boolean, it will be interpreted loosely. 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.
When the user checks or unchecks the checkbox, KO will set your model property to true or false accordingly.
Special consideration is given if your parameter resolves to an array. In this case, KO will set the element to be checked if the value matches an item in the array, and unchecked if it is not contained in the array.
When the user checks or unchecks the checkbox, KO will add or remove the value from the array accordingly.
For radio buttons, KO will set the element to be checked if and only if the parameter value equals the radio button node's value attribute or the value specified by the checkedValue parameter. In the previous example, the radio button with value="almond" was checked only when the view model's spamFlavor property was equal to "almond".
When the user changes which radio button is selected, KO will set your model property to equal the value of the selected radio button. In the preceding example, clicking on the radio button with value="cherry" would set viewModel.spamFlavor to be "cherry".
Of course, this is most useful when you have multiple radio button elements bound to a single model property. To ensure that only one of those radio buttons can be checked at any one time, you should set all of their name attributes to an arbitrary common value (e.g., the value flavorGroup in the preceding example) - doing this puts them into a group where only one can be selected.
If your parameter is an observable value, the binding will update the element's checked state whenever the value changes. If the parameter isn't observable, it will only set the element's checked state once and will not update it again later.
Additional parameters
checkedValue
If your binding also includes checkedValue, this defines the value used by the checked binding instead of the element's value attribute. This is useful if you want the value to be something other than a string (such as an integer or object), or you want the value set dynamically.
In the following example, the item objects themselves (not their itemName strings) will be included in the chosenItems array when their corresponding checkboxes are checked:
<!-- ko foreach: items -->
<input type="checkbox" data-bind="checkedValue: $data, checked: $root.chosenItems" />
<span data-bind="text: itemName"></span>
<!-- /ko -->
var viewModel = {
items: ko.observableArray([
{ itemName: 'Choice 1' },
{ itemName: 'Choice 2' }
]),
chosenItems: ko.observableArray()
};
If your checkedValue parameter is an observable value, whenever the value changes and the element is currently checked, the binding will update the checked model property. For checkboxes, it will remove the old value from the array and add the new value. For radio buttons, it will just update the model value.
The click binding adds an event handler so that your chosen JavaScript function will be invoked when the associated DOM element is clicked. This is most commonly used with elements like button, input, and a, but actually works with any visible DOM element.
Each time you click the button, this will invoke incrementClickCounter() on the view model, which in turn changes the view model state, which causes the UI to update.
Main parameter
The function you want to bind to the element's click event.
You can reference any JavaScript function - it doesn't have to be a function on your view model. You can reference a function on any object by writing click: someObject.someFunction.
Additional parameters
When calling your handler, Knockout will supply the current model value as the first parameter. This is particularly useful if you're rendering some UI for each item in a collection, and you need to know which item's UI was clicked. For example,
Two points to note about this example:
foreach or a with block, but your handler function
is on the root viewmodel or some other parent context, you'll need to use a prefix such as $parent or $root to locate the
handler function.self (or some other variable) as an alias for this. Doing so avoids any problems
with this being redefined to mean something else in event handlers or Ajax request callbacks.In some scenarios, you may need to access the DOM event object associated with your click event. Knockout will pass the event as the second parameter to your function, as in this example:
If you need to pass more parameters, one way to do it is by wrapping your handler in a function literal that takes in a parameter, as in this example:
<button data-bind="click: function(data, event) { myFunction('param1', 'param2', data, event) }">
Click me
</button>
Now, KO will pass the data and event objects to your function literal, which are then available to be passed to your handler.
Alternatively, if you prefer to avoid the function literal in your view, you can use the bind function, which attaches specific parameter values to a function reference:
<button data-bind="click: myFunction.bind($data, 'param1', 'param2')">
Click me
</button>
By default, Knockout will prevent the click event from taking any default action. This means that if you use the click binding on an a tag (a link), for example, the browser will only call your handler function and will not navigate to the link's href. This is a useful default because when you use the click binding, it's normally because you're using the link as part of a UI that manipulates your view model, not as a regular hyperlink to another web page.
However, if you do want to let the default click action proceed, just return true from your click handler function.
By default, Knockout will allow the click event to continue to bubble up to any higher level event handlers. For example, if your element and a parent of that element are both handling the click event, then the click handler for both elements will be triggered. If necessary, you can prevent the event from bubbling by including an additional binding that is named clickBubble and passing false to it, as in this example:
<div data-bind="click: myDivHandler">
<button data-bind="click: myButtonHandler, clickBubble: false">
Click me
</button>
</div>
Normally, in this case myButtonHandler would be called first, then the click event would bubble up to myDivHandler. However, the clickBubble binding that we added with a value of false prevents the event from making it past myButtonHandler.
The component binding injects a specified component into an element, and optionally passes parameters to it.
Note: In more realistic cases, you would typically load component viewmodels and templates from external files, instead of hardcoding them into the registration. See an example and registration documentation.
There are two ways to use the component binding:
Shorthand syntax
If you pass just a string, it is interpreted as a component name. The named component is then injected without supplying any parameters to it. Example:
<div data-bind='component: "my-component"'></div>
The shorthand value can also be observable. In this case, if it changes, the component binding will dispose the old component instance, and inject the newly-referenced component. Example:
<div data-bind='component: observableWhoseValueIsAComponentName'></div>
Full syntax
To supply parameters to the component, pass an object with the following properties:
name --- the name of the component to inject. Again, this can be observable.params --- an object that will be passed on to the component. Typically this is a key-value object containing multiple parameters, and is typically received by the component's viewmodel constructor.Example:
<div data-bind='component: {
name: "shopping-cart",
params: { mode: "detailed-list", items: productsList }
}'></div>
Note that whenever a component is removed (either because the name observable changed, or because an enclosing control-flow binding removed the entire element), the removed component is disposed
When a component binding injects a component,
Your component loaders are asked to supply the viewmodel factory and template
Normally, this is an asynchronous process. It may involve requests to the server. For API consistency, Knockout by default ensures that the loading process completes as an asynchronous callback even if the component is already loaded and cached in memory. For more about this, and how to allow synchronous loading, see Controlling synchronous/asynchronous loading.
The component template is cloned and injected into the container element
Any existing content is removed and discarded.
If the component has a viewmodel, it is instantiated
If the viewmodel is given as a constructor function, this means Knockout calls new YourViewModel(params).
If the viewmodel is given as a createViewModel factory function, Knockout calls createViewModel(params, componentInfo), where componentInfo.element is the element into which the not-yet-bound template has already been injected.
This phase always completes synchronously (constructors and factory functions are not allowed to be asynchronous), since it occurs every time a component is instantiated and performance would be unacceptable if it involved waiting for network requests.
The viewmodel is bound to the view
Or, if the component has no viewmodel, then the view is bound to any params you've supplied to the component binding.
The component is active
Now the component is operating, and can remain on-screen for as long as needed.
If any of the parameters passed to the component is observable, then the component can of course observe any changes, or even write back modified values. This is how it can communicate cleanly with its parent, without tightly coupling the component code to any parent that uses it.
The component is torn down, and the viewmodel is disposed
If the component binding's name value changes observably, or if an enclosing control-flow binding causes the container element to be removed, then any dispose function on the viewmodel is called just before the container element is removed from the DOM. See also: disposal and memory management.
Note: If the user navigates to an entirely different web page, browsers do this without asking any code running in the page to clean up. So in this case no dispose functions will be invoked. This is OK because the browser will automatically release the memory used by all objects that were in use.
Components usually have viewmodels, but they don't necessarily have to. A component can specify just a template.
In this case, the object to which the component's view is bound is the params object that you passed to the component binding. Example:
ko.components.register('special-offer', {
template: '<div class="offer-box" data-bind="text: productName"></div>'
});
... can be injected with:
<div data-bind='component: {
name: "special-offer-callout",
params: { productName: someProduct.name }
}'></div>
... or, more conveniently, as a custom element:
<special-offer params='productName: someProduct.name'></special-offer>
component without a container elementSometimes you may want to inject a component into a view without using an extra container element. You can do this using containerless control flow syntax, which is based on comment tags. For example,
<!-- ko component: "message-editor" -->
<!-- /ko -->
... or passing parameters:
<!-- ko component: {
name: "message-editor",
params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->
The <!-- ko --> and <!-- /ko --> comments act as start/end markers, defining a "virtual element" that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.
The element you attach a component binding to may contain further markup. For example,
<div data-bind="component: { name: 'my-special-list', params: { items: someArrayOfPeople } }">
<!-- Look, here's some arbitrary markup. By default it gets stripped out
and is replaced by the component output. -->
The person <em data-bind="text: name"></em>
is <em data-bind="text: age"></em> years old.
</div>
Although the DOM nodes in this element will be stripped out and not bound by default, they are not lost. Instead, they are supplied to the component (in this case, my-special-list), which can include them in its output however it wishes.
This is useful if you want to build components that represent "container" UI elements, such as grids, lists, dialogs, or tab sets, which need to inject and bind arbitrary markup into a common structure. See a complete example for custom elements, which also works without custom elements using the syntax shown above.
Optionally, your viewmodel class may have a dispose function. If implemented, Knockout will call this whenever the component is being torn down and removed from the DOM (e.g., because the corresponding item was removed from a foreach, or an if binding has become false).
You must use dispose to release any resources that aren't inherently garbage-collectable. For example:
setInterval callbacks will continue to fire until explicitly cleared.clearInterval(handle) to stop them, otherwise your viewmodel might be held in memory.ko.computed properties continue to receive notifications from their dependencies until explicitly disposed..dispose() on the computed property, otherwise it (and possibly also your viewmodel) will be held in memory. Alternatively, consider using a pure computed to avoid the need for manual disposal..dispose() on the subscription, otherwise the callback (and possibly also your viewmodel) will be held in memory.createViewModel function (or even inside a regular component viewmodel, although to fit the MVVM pattern you shouldn't) must be removed.For example:
var someExternalObservable = ko.observable(123);
function SomeComponentViewModel() {
this.myComputed = ko.computed(function() {
return someExternalObservable() + 1;
}, this);
this.myPureComputed = ko.pureComputed(function() {
return someExternalObservable() + 2;
}, this);
this.mySubscription = someExternalObservable.subscribe(function(val) {
console.log('The external observable changed to ' + val);
}, this);
this.myIntervalHandle = window.setInterval(function() {
console.log('Another second passed, and the component is still alive.');
}, 1000);
}
SomeComponentViewModel.prototype.dispose = function() {
this.myComputed.dispose();
this.mySubscription.dispose();
window.clearInterval(this.myIntervalHandle);
// this.myPureComputed doesn't need to be manually disposed.
}
ko.components.register('your-component-name', {
viewModel: SomeComponentViewModel,
template: 'some template'
});
It isn't strictly necessary to dispose computeds and subscriptions that only depend on properties of the same viewmodel object, since this creates only a circular reference which JavaScript garbage collectors know how to release. However, to avoid having to remember which things need disposal, you may prefer to use pureComputed wherever possible, and explicitly dispose all other computeds/subscriptions whether technically necessary or not.
Custom elements provide a convenient way of injecting components into your views.
Custom elements are a syntactical alternative to the component binding (and in fact, custom elements make use of a component binding behind the scenes).
For example, instead of writing this:
<div data-bind='component: { name: "flight-deals", params: { from: "lhr", to: "sfo" } }'></div>
... you can write:
<flight-deals params='from: "lhr", to: "sfo"'></flight-deals>
This allows for a very modern, WebComponents-like way to organize your code, while retaining support for even very old browsers (see custom elements and IE 6 to 8).
This example declares a component, and then injects two instances of it into a view. See the source code below.
<live-example params='id: "component-custom-element"'></live-example>
Note: In more realistic cases, you would typically load component viewmodels and templates from external files, instead of hardcoding them into the registration. See an example and registration documentation.
As you have seen in the examples above, you can use a params attribute to supply parameters to the component viewmodel. The contents of the params attribute are interpreted like a JavaScript object literal (just like a data-bind attribute), so you can pass arbitrary values of any type. Example:
<unrealistic-component
params='stringValue: "hello",
numericValue: 123,
boolValue: true,
objectValue: { a: 1, b: 2 },
dateValue: new Date(),
someModelProperty: myModelValue,
observableSubproperty: someObservable().subprop'>
</unrealistic-component>
If you refer to model properties in a params attribute, then you are of course referring to the properties on the viewmodel outside the component (the 'parent' or 'host' viewmodel), since the component itself is not instantiated yet. In the above example, myModelValue would be a property on the parent viewmodel, and would be received by the child component viewmodel's constructor as params.someModelProperty.
This is how you can pass properties from a parent viewmodel to a child component. If the properties themselves are observable, then the parent viewmodel will be able to observe and react to any new values inserted into them by the child component.
In the following example,
<some-component
params='simpleExpression: 1 + 1,
simpleObservable: myObservable,
observableExpression: myObservable() + 1'>
</some-component>
... the component viewmodel's params parameter will contain three values:
simpleExpression
This will be the numeric value 2. It will not be an observable or computed value, since there are no observables involved.
In general, if a parameter's evaluation does not involve evaluating an observable (in this case, the value did not involve observables at all), then the value is passed literally. If the value was an object, then the child component could mutate it, but since it's not observable the parent would not know the child had done so.
simpleObservable
This will be the ko.observable instance declared on the parent viewmodel as myObservable. It is not a wrapper --- it's the actual same instance as referenced by the parent. So if the child viewmodel writes to this observable, the parent viewmodel will receive that change.
In general, if a parameter's evaluation does not involve evaluating an observable (in this case, the observable was simply passed without evaluating it), then the value is passed literally.
observableExpression
This one is trickier. The expression itself, when evaluated, reads an observable. That observable's value could change over time, so the expression result could change over time.
To ensure that the child component can react to changes in the expression value, Knockout automatically upgrades this parameter to a computed property. So, the child component will be able to read params.observableExpression() to get the current value, or use params.observableExpression.subscribe(...), etc.
In general, with custom elements, if a parameter's evaluation involves evaluating an observable, then Knockout automatically constructs a ko.computed value to give the expression's result, and supplies that to the component.
In summary, the general rule is:
Sometimes you may want to create a component that receives markup and uses it as part of its output. For example, you may want to build a "container" UI element such as a grid, list, dialog, or tab set that can receive and bind arbitrary markup inside itself.
Consider a special list component that can be invoked as follows:
<my-special-list params="items: someArrayOfPeople">
<!-- Look, I'm putting markup inside a custom element -->
The person <em data-bind="text: name"></em>
is <em data-bind="text: age"></em> years old.
</my-special-list>
By default, the DOM nodes inside <my-special-list> will be stripped out (without being bound to any viewmodel) and replaced by the component's output. However, those DOM nodes aren't lost: they are remembered, and are supplied to the component in two ways:
$componentTemplateNodes, available to any binding expression in the component's template (i.e., as a binding context property). Usually this is the most convenient way to use the supplied markup. See the example below.componentInfo.templateNodes, passed to its createViewModel functionThe component can then choose to use the supplied DOM nodes as part of its output however it wishes, such as by using template: { nodes: $componentTemplateNodes } on any element in the component's template.
For example, the my-special-list component's template can reference $componentTemplateNodes so that its output includes the supplied markup. Here's the complete working example:
This "special list" example does nothing more than insert a heading above each list item. But the same technique can be used to create sophisticated grids, dialogs, tab sets, and so on, since all that is needed for such UI elements is common UI markup (e.g., to define the grid or dialog's heading and borders) wrapped around arbitrary supplied markup.
This technique is also possible when using components without custom elements, i.e., passing markup when using the component binding directly.
By default, Knockout assumes that your custom element tag names correspond exactly to the names of components registered using ko.components.register. This convention-over-configuration strategy is ideal for most applications.
If you want to have different custom element tag names, you can override getComponentNameForNode to control this. For example,
ko.components.getComponentNameForNode = function(node) {
var tagNameLower = node.tagName && node.tagName.toLowerCase();
if (ko.components.isRegistered(tagNameLower)) {
// If the element's name exactly matches a preregistered
// component, use that component
return tagNameLower;
} else if (tagNameLower === "special-element") {
// For the element <special-element>, use the component
// "MySpecialComponent" (whether or not it was preregistered)
return "MySpecialComponent";
} else {
// Treat anything else as not representing a component
return null;
}
}
You can use this technique if, for example, you want to control which subset of registered components may be used as custom elements.
If you are using the default component loader, and hence are registering your components using ko.components.register, then there is nothing extra you need to do. Components registered this way are immediately available for use as custom elements.
If you have implemented a custom component loader, and are not using ko.components.register, then you need to tell Knockout about any element names you wish to use as custom elements. To do this, simply call ko.components.register - you don't need to specify any configuration, since your custom component loader won't be using the configuration anyway. For example,
ko.components.register('my-custom-element', { /* No config needed */ });
Alternatively, you can override getComponentNameForNode to control dynamically which elements map to which component names, independently of preregistration.
A custom element can have a regular data-bind attribute (in addition to any params attribute) if needed. For example,
<products-list params='category: chosenCategory'
data-bind='visible: shouldShowProducts'>
</products-list>
However, it does not make sense to use bindings that would modify the element's contents, such as the text or template bindings, since they would overwrite the template injected by your component.
Knockout will prevent the use of any bindings that use controlsDescendantBindings, because this also would clash with the component when trying to bind its viewmodel to the injected template. Therefore if you want to use a control flow binding such as if or foreach, then you must wrap it around your custom element rather than using it directly on the custom element, e.g.,:
<!-- ko if: someCondition -->
<products-list></products-list>
<!-- /ko -->
or:
<ul data-bind='foreach: allProducts'>
<product-details params='product: $data'></product-details>
</ul>
You must write <my-custom-element></my-custom-element>, and not <my-custom-element />. Otherwise, your custom element is not closed and subsequent elements will be parsed as child elements.
This is a limitation of the HTML specification and is outside the scope of what Knockout can control. HTML parsers, following the HTML specification, ignore any self-closing slashes (except on a small number of special "foreign elements", which are hardcoded into the parser). HTML is not the same as XML.
Knockout tries hard to spare developers the pain of dealing with cross-browser compatiblity issues, especially those relating to older browsers! Even though custom elements provide a very modern style of web development, they still work on all commonly-encountered browsers:
IE 6-8's HTML parser will discard any unrecognized elements. To ensure it doesn't throw out your custom elements, you must do one of the following:
ko.components.register('your-component') before the HTML parser sees any <your-component> elementsdocument.createElement('your-component') before the HTML parser sees any <your-component> elements. You can ignore the result of the createElement call --- all that matters is that you have called it.For example, if you structure your page like this, then everything will be OK:
<!DOCTYPE html>
<html>
<body>
<script src='some-script-that-registers-components.js'></script>
<my-custom-element></my-custom-element>
</body>
</html>
If you're working with AMD, then you might prefer a structure like this:
<!DOCTYPE html>
<html>
<body>
<script>
// Since the components aren't registered until the AMD module
// loads, which is asynchronous, the following prevents IE6-8's
// parser from discarding the custom element
document.createElement('my-custom-element');
</script>
<script src='require.js' data-main='app/startup'></script>
<my-custom-element></my-custom-element>
</body>
</html>
Or if you really don't like the hackiness of the document.createElement call, then you could use a component binding for your top-level component instead of a custom element. As long as all other components are registered before your ko.applyBindings call, they can be used as custom elements on IE6-8 without futher trouble:
<!DOCTYPE html>
<html>
<body>
<!-- The startup module registers all other KO components before calling
ko.applyBindings(), so they are OK as custom elements on IE6-8 -->
<script src='require.js' data-main='app/startup'></script>
<div data-bind='component: "my-custom-element"'></div>
</body>
</html>
$raw parametersConsider the following unusual case, in which useObservable1, observable1, and observable2 are all observables:
<some-component
params='myExpr: useObservable1() ? observable1 : observable2'>
</some-component>
Since evaluating myExpr involves reading an observable (useObservable1), KO will supply the parameter to the component as a computed property.
However, the value of the computed property is itself an observable. This would seem to lead to an awkward scenario, where reading its current value would involve double-unwrapping (i.e., params.myExpr()(), where the first parentheses give the value of the expression, and the second give the value of the resulting observable instance).
This double-unwrapping would be ugly, inconvenient, and unexpected, so Knockout automatically sets up the generated computed property (params.myExpr) to unwrap its value for you. That is, the component can read params.myExpr() to get the value of whichever observable has been selected (observable1 or observable2), without the need for double-unwrapping.
In the unlikely event that you don't want the automatic unwrapping, because you want to access the observable1/observable2 instances directly, you can read values from params.$raw. For example,
function MyComponentViewModel(params) {
var currentObservableInstance = params.$raw.myExpr();
// Now currentObservableInstance is either observable1 or observable2
// and you would read its value with "currentObservableInstance()"
}
This should be a very unusual scenario, so normally you will not need to work with $raw.
Whenever you inject a component using the component binding or a custom element, Knockout fetches that component's template and viewmodel using one or more component loaders. The job of a component loader is to asynchronously supply a template/viewmodel pair for any given component name.
The built-in default component loader, ko.components.defaultLoader, is based around a central "registry" of component definitions. It relies on you explicitly registering a configuration for each component before you can use that component.
Learn more about configuring and registering components with the default loader
The following functions read and write the default component loader's registry:
ko.components.register(name, configuration)
ko.components.isRegistered(name)
true if a component with the specified name is already registered; false otherwise.ko.components.unregister(name)
The following functions work across the complete list of registered component loaders (not only the default loader):
ko.components.get(name, callback)
callback to return than viewmodel/template declaration. Invokes callback(null) if none of the registered loaders know about this component.ko.components.clearCachedDefinition(name)
Also, since ko.components.defaultLoader is a component loader, it implements the following standard component loader functions. You can invoke these directly, e.g., as part of your implementation of a custom loader:
ko.components.defaultLoader.getConfig(name, callback)ko.components.defaultLoader.loadComponent(name, componentConfig, callback)ko.components.defaultLoader.loadTemplate(name, templateConfig, callback)ko.components.defaultLoader.loadViewModel(name, viewModelConfig, callback)For documentation on these standard component loader functions, see implementing a custom component loader.
You might want to implement a custom component loader if you want to use naming conventions, rather than explicit registration, to load components. Or, if you want to use a third-party "loader" library to fetch component viewmodels or templates from external locations.
A custom component loader is simply an object whose properties are any combination of the following functions:
getConfig(name, callback)Define this if: you want to supply configurations programmatically based on names, e.g., to implement a naming convention.
If declared, Knockout will call this function to obtain a configuration object for each component being instantiated.
callback(componentConfig), where componentConfig is any object that can be understood by the loadComponent function on your loader or any other loader. The default loader simply supplies whatever object was registered using ko.components.register.componentConfig like { template: 'someElementId', viewModel: { require: 'myModule' } } can be understood and instantiated by the default loader.loadComponent function understands them.callback(null). Knockout will then consult any other registered loaders in sequence, until one supplies a non-null value.loadComponent(name, componentConfig, callback)Define this if: you want to take control over how component configurations are interpreted, e.g., if you do not want to use the standard viewModel/template pair format.
If declared, Knockout will call this function to convert a componentConfig object into a viewmodel/template pair.
To supply a viewmodel/template pair, call callback(result), where result is an object with the following properties:
template - Required. An array of DOM nodescreateViewModel(params, componentInfo) - Optional. A function that will later be called to supply a viewmodel object for each instance of this componentIf you do not want your loader to supply a viewmodel/template pair for the given parameters, then call callback(null). Knockout will then consult any other registered loaders in sequence, until one supplies a non-null value.
loadTemplate(name, templateConfig, callback)Define this if: you want to use custom logic to supply DOM nodes for a given template configuration (e.g., using an ajax request to fetch a template by URL).
The default component loader will call this function on any registered loaders that declare it, to convert the template part of a component configuration into an array of DOM nodes. The nodes are then cached and cloned for each instance of the component.
The templateConfig value is simply the template property from any componentConfig object. For example, it may contain "some markup" or { element: "someId" } or a custom format such as { loadFromUrl: "someUrl.html" }.
To supply an array of DOM nodes, call callback(domNodeArray).
If you do not want your loader to supply a template for the given parameters (e.g., because it does not recognize the configuration format), call callback(null). Knockout will then consult any other registered loaders in sequence, until one supplies a non-null value.
loadViewModel(name, templateConfig, callback)Define this if: you want to use custom logic to supply a viewmodel factory for a given viewmodel configuration (e.g., integrating with a third-party module loader or dependency injection system).
The default component loader will call this function on any registered loaders that declare it, to convert the viewModel part of a component configuration into a createViewModel factory function. The function is then cached and called for each new instance of the component that needs a viewmodel.
The viewModelConfig value is simply the viewModel property from any componentConfig object. For example, it may be a constructor function, or a custom format such as { myViewModelType: 'Something', options: {} }.
To supply a createViewModel function, call callback(yourCreateViewModelFunction). The createViewModel function must accept parameters (params, componentInfo) and must synchronously return a new viewmodel instance each time it is called.
If you do not want your loader to supply a createViewModel function for the given parameters (e.g., because it does not recognize the configuration format), call callback(null). Knockout will then consult any other registered loaders in sequence, until one supplies a non-null value.
Knockout allows you to use multiple component loaders simultaneously. This is useful so that, for example, you can plug in loaders that implement different mechanisms (e.g., one might fetch templates from a backend server according to a naming convention; another might set up viewmodels using a dependency injection system) and have them work together.
So, ko.components.loaders is an array containing all the loaders currently enabled. By default, this array contains just one item: ko.components.defaultLoader. To add additional loaders, simply insert them into the ko.components.loaders array.
If you want your custom loader to take precedence over the default loader (so it gets the first opportunity to supply configuration/values), then add it to the beginning of the array. If you want the default loader to take precedence (so your custom loader is only called for components not explicitly registered), then add it to the end of the array.
Example:
// Adds myLowPriorityLoader to the end of the loaders array.
// It runs after other loaders, only if none of them returned a value.
ko.components.loaders.push(myLowPriorityLoader);
// Adds myHighPriorityLoader to the beginning of the loaders array.
// It runs before other loaders, getting the first chance to return values.
ko.components.loaders.unshift(myHighPriorityLoader)
If required, you can remove ko.components.defaultLoader from the loaders array altogether.
The first time Knockout needs to construct a component with a given name, it:
getConfig functions in turn, until the first one supplies a non-null componentConfig.componentConfig object, calls each of the registered loaders' loadComponent functions in turn, until the first one supplies a non-null template/createViewModel pair.When the default loader's loadComponent runs, it simultaneously:
Calls each of the registered loaders' loadTemplate functions in turn, until the first one supplies a non-null DOM array.
loadTemplate function that resolves a range of template configuration formats into DOM arrays.Calls each of the registered loaders' loadViewModel functions in turn, until the first one supplies a non-null createViewModel function.
loadViewModel function that resolves a range of viewmodel configuration formats into createViewModel functions.Custom loaders can plug into any part of this process, so you can take control over supplying configurations, interpreting configurations, supplying DOM nodes, or supplying viewmodel factory functions. By putting custom loaders into a chosen order inside ko.components.loaders, you can control the priority order of different loading strategies.
To implement a naming convention, your custom component loader only needs to implement getConfig. For example:
var namingConventionLoader = {
getConfig: function(name, callback) {
// 1. Viewmodels are classes corresponding to the component name.
// e.g., my-component maps to MyApp.MyComponentViewModel
// 2. Templates are in elements whose ID is the component name
// plus '-template'.
var viewModelConfig = MyApp[toPascalCase(name) + 'ViewModel'],
templateConfig = { element: name + '-template' };
callback({ viewModel: viewModelConfig, template: templateConfig });
}
};
function toPascalCase(dasherized) {
return dasherized.replace(/(^|-)([a-z])/g, function (g, m1, m2) { return m2.toUpperCase(); });
}
// Register it. Make it take priority over the default loader.
ko.components.loaders.unshift(namingConventionLoader);
Now this is registered, you can reference components with any name (without preregistering them), e.g.:
<div data-bind="component: 'my-component'"></div>
<!-- Declare template -->
<template id='my-component-template'>Hello World!</template>
<script>
// Declare viewmodel
window.MyApp = window.MyApp || {};
MyApp.MyComponentViewModel = function(params) {
// ...
}
</script>
If your custom loader implements loadTemplate and/or loadViewModel, then you can plug in custom code to the loading process. You can also use these functions to interpret custom configuration formats.
For example, you might want to enable configuration formats like the following:
ko.components.register('my-component', {
template: { fromUrl: 'file.html', maxCacheAge: 1234 },
viewModel: { viaLoader: '/path/myvm.js' }
});
... and you can do so using custom loaders.
The following custom loader will take care of loading templates configured with a fromUrl value:
var templateFromUrlLoader = {
loadTemplate: function(name, templateConfig, callback) {
if (templateConfig.fromUrl) {
// Uses jQuery's ajax facility to load the markup from a file
var fullUrl = '/templates/' + templateConfig.fromUrl + '?cacheAge=' + templateConfig.maxCacheAge;
$.get(fullUrl, function(markupString) {
// We need an array of DOM nodes, not a string.
// We can use the default loader to convert to the
// required format.
ko.components.defaultLoader.loadTemplate(name, markupString, callback);
});
} else {
// Unrecognized config format. Let another loader handle it.
callback(null);
}
}
};
// Register it
ko.components.loaders.unshift(templateFromUrlLoader);
... and the following custom loader will take care of loading viewmodels configured with a viaLoader value:
var viewModelCustomLoader = {
loadViewModel: function(name, viewModelConfig, callback) {
if (viewModelConfig.viaLoader) {
// You could use arbitrary logic, e.g., a third-party
// code loader, to asynchronously supply the constructor.
// For this example, just use a hard-coded constructor function.
var viewModelConstructor = function(params) {
this.prop1 = 123;
};
// We need a createViewModel function, not a plain constructor.
// We can use the default loader to convert to the
// required format.
ko.components.defaultLoader.loadViewModel(name, viewModelConstructor, callback);
} else {
// Unrecognized config format. Let another loader handle it.
callback(null);
}
}
};
// Register it
ko.components.loaders.unshift(viewModelCustomLoader);
If you prefer, you could combine templateFromUrlLoader and viewModelCustomLoader into a single loader by putting the loadTemplate and loadViewModel functions on a single object. However it's quite nice to separate out these concerns, since their implementations are quite independent.
If you are using a component loader to fetch components by a naming convention, and are not registering your components using ko.components.register, then those components will not automatically be usable as custom elements (because you haven't told Knockout that they even exist).
See: How to enable custom elements with names that don't correspond to explicitly registered components
Browserify is a popular library for referencing JavaScript libraries with a Node-style synchronous require syntax. It's often considered as an alternative to an AMD loader such as require.js. However Browserify solves a rather different problem: synchronous build-time reference resolution, rather than asynchronous runtime reference resolution as handled by AMD.
Since Browserify is a build-time tool, it doesn't really need any special integration with KO components, and there's no need to implement any kind of custom component loader to work with it. You can simply use Browserify's require statements to grab instances of your component viewmodels, then explicitly register them, e.g.:
// Note that the following *only* works with Browserify - not with require.js,
// since it relies on require() returning synchronously.
ko.components.register('my-browserify-component', {
viewModel: require('myViewModel'),
template: require('fs').readFileSync(__dirname + '/my-template.html', 'utf8')
});
This uses the brfs Browserify plugin to automatically inline the .html file, so you would need to build the script file using a command similar to:
npm install brfsbrowserify -t brfs main.js > bundle.jsComponents are a powerful, clean way of organizing your UI code into self-contained, reusable chunks. They:
This pattern is beneficial for large applications, because it simplifies development through clear organization and encapsulation, and helps to improve runtime performance by incrementally loading your application code and templates as needed.
Custom elements are an optional but convenient syntax for consuming components. Instead of needing placeholder <div>s into which components are injected with bindings, you can use more self-descriptive markup with custom element names (e.g., <voting-button> or <product-editor>). Knockout takes care to ensure compatibility even with old browsers such as IE 6.
To get started, you can register a component using ko.components.register (technically, registration is optional, but it's the easiest way to get started). A component definition specifies a viewModel and template. For example:
Normally, you'd load the view model and template from external files instead of declaring them inline like this. We'll get to that later.
Now, to use this component, you can reference it from any other view in your application, either using the component binding or using a custom element. Here's a live example that uses it as a custom element:
In this example, the component both displays and edits an observable property called userRating on the Product view model class.
In most applications, you'll want to keep component view models and templates in external files. If you configure Knockout to fetch them via an AMD module loader such as require.js, then they can either be preloaded (possibly bundled/minified), or incrementally loaded as needed.
Here's an example configuration:
ko.components.register('like-or-dislike', {
viewModel: { require: 'files/component-like-widget' },
template: { require: 'text!files/component-like-widget.html' }
});
Requirements
For this to work, the files files/component-like-widget.js and files/component-like-widget.html need to exist. Check them out (and view source on the .html one) - as you'll see, this is cleaner and more convenient that including the code inline in the definition.
Also, you need to have referenced a suitable module loader library (such as require.js) or implemented a custom component loader that knows how to grab your files.
Using the component
Now like-or-dislike can be consumed in the same way as before, using either a component binding or a custom element:
<ul data-bind="foreach: products">
<li class="product">
<strong data-bind="text: name"></strong>
<like-or-dislike params="value: userRating"></like-or-dislike>
</li>
</ul>
<button data-bind="click: addProduct">Add a product</button>
function Product(name, rating) {
this.name = name;
this.userRating = ko.observable(rating || null);
}
function MyViewModel() {
this.products = ko.observableArray(); // Start empty
}
MyViewModel.prototype.addProduct = function() {
var name = 'Product ' + (this.products().length + 1);
this.products.push(new Product(name));
};
ko.applyBindings(new MyViewModel());
If you open your browser developer tools' Network inspector before your first click on Add product, you'll see that the component's .js/.html files are fetched on demand when first required, and thereafter retained for reuse.
More more detailed information, see:
component bindingFor Knockout to be able to load and instantiate your components, you must register them using ko.components.register, providing a configuration as described here.
Note: As an alternative, it's possible to implement a custom component loader that fetches components by your own conventions instead of explicit configuration.
You can register a component as follows:
ko.components.register('some-component-name', {
viewModel: <see below>,
template: <see below>
});
your-component-name) so that the component name is valid to use as a custom element (such as <your-component-name>).viewModel is optional, and can take any of the viewModel formats described below.template is required, and can take any of the template formats described below.If no viewmodel is given, the component is treated as a simple block of HTML that will be bound to any parameters passed to the component.
Viewmodels can be specified in any of the following forms:
function SomeComponentViewModel(params) {
// 'params' is an object whose key/value pairs are the parameters
// passed from the component binding or custom element.
this.someProperty = params.something;
}
SomeComponentViewModel.prototype.doSomething = function() { ... };
ko.components.register('my-component', {
viewModel: SomeComponentViewModel,
template: ...
});
Knockout will invoke your constructor once for each instance of the component, producing a separate viewmodel object for each. Properties on the resulting object or its prototype chain (e.g., someProperty and doSomething in the example above) are available for binding in the component's view.
If you want all instances of your component to share the same viewmodel object instance (which is not usually desirable):
var sharedViewModelInstance = { ... };
ko.components.register('my-component', {
viewModel: { instance: sharedViewModelInstance },
template: ...
});
Note that it's necessary to specify viewModel: { instance: object }, and not just viewModel: object. This differentiates from the other cases below.
createViewModel factory functionIf you want to run any setup logic on the associated element before it is bound to the viewmodel, or use arbitrary logic to decide which viewmodel class to instantiate:
ko.components.register('my-component', {
viewModel: {
createViewModel: function(params, componentInfo) {
// - 'params' is an object whose key/value pairs are the parameters
// passed from the component binding or custom element
// - 'componentInfo.element' is the element the component is being
// injected into. When createViewModel is called, the template has
// already been injected into this element, but isn't yet bound.
// - 'componentInfo.templateNodes' is an array containing any DOM
// nodes that have been supplied to the component. See below.
// Return the desired view model instance, e.g.:
return new MyViewModel(params);
}
},
template: ...
});
Note that, typically, it's best to perform direct DOM manipulation only through custom bindings rather than acting on componentInfo.element from inside createViewModel. This leads to more modular, reusable code.
The componentInfo.templateNodes array is useful if you want to build a component that accepts arbitrary markup to influence its output (for example, a grid, list, dialog, or tab set that injects supplied markup into itself). For a complete example, see passing markup into components.
If you have an AMD loader (such as require.js) already in your page, then you can use it to fetch a viewmodel. For more details about how this works, see how Knockout loads components via AMD below. Example:
ko.components.register('my-component', {
viewModel: { require: 'some/module/name' },
template: ...
});
The returned AMD module object can be in any of the forms allowed for viewmodels. So, it can be a constructor function, e.g.:
// AMD module whose value is a component viewmodel constructor
define(['knockout'], function(ko) {
function MyViewModel() {
// ...
}
return MyViewModel;
});
... or a shared object instance, e.g.:
// AMD module whose value is a shared component viewmodel instance
define(['knockout'], function(ko) {
function MyViewModel() {
// ...
}
return { instance: new MyViewModel() };
});
... or a createViewModel function, e.g.:
// AMD module whose value is a 'createViewModel' function
define(['knockout'], function(ko) {
function myViewModelFactory(params, componentInfo) {
// return something
}
return { createViewModel: myViewModelFactory };
});
... or even, though it's unlikely you'd want to do this, a reference to a different AMD module, e.g.:
// AMD module whose value is a reference to a different AMD module,
// which in turn can be in any of these formats
define(['knockout'], function(ko) {
return { module: 'some/other/module' };
});
Templates can be specified in any of the following forms. The most commonly useful are existing element IDs and AMD modules.
For example, the following element:
<template id='my-component-template'>
<h1 data-bind='text: title'></h1>
<button data-bind='click: doSomething'>Click me right now</button>
</template>
... can be used as the template for a component by specifying its ID:
ko.components.register('my-component', {
template: { element: 'my-component-template' },
viewModel: ...
});
Note that only the nodes inside the specified element will be cloned into each instance of the component. The container element (in this example, the <template> element), will not be treated as part of the component template.
You're not limited to using <template> elements, but these are convenient (on browsers that support them) since they don't get rendered on their own. Any other element type works too.
If you have a reference to a DOM element in your code, you can use it as a container for template markup:
var elemInstance = document.getElementById('my-component-template');
ko.components.register('my-component', {
template: { element: elemInstance },
viewModel: ...
});
Again, only the nodes inside the specified element will be cloned for use as the component's template.
ko.components.register('my-component', {
template: '<h1 data-bind="text: title"></h1>\
<button data-bind="click: doSomething">Clickety</button>',
viewModel: ...
});
This is mainly useful when you're fetching the markup from somewhere programmatically (e.g., AMD - see below), or as a build system output that packages components for distribution, since it's not very convenient to manually edit HTML as a JavaScript string literal.
If you're building configurations programmatically and you have an array of DOM nodes, you can use them as a component template:
var myNodes = [
document.getElementById('first-node'),
document.getElementById('second-node'),
document.getElementById('third-node')
];
ko.components.register('my-component', {
template: myNodes,
viewModel: ...
});
In this case, all the specified nodes (and their descendants) will be cloned and concatenated into each copy of the component that gets instantiated.
If you're building configurations programmatically and you have a DocumentFragment object, you can use it as a component template:
ko.components.register('my-component', {
template: someDocumentFragmentInstance,
viewModel: ...
});
Since document fragments can have multiple top-level nodes, the entire document fragment (not just descendants of top-level nodes) is treated as the component template.
If you have an AMD loader (such as require.js) already in your page, then you can use it to fetch a template. For more details about how this works, see how Knockout loads components via AMD below. Example:
ko.components.register('my-component', {
template: { require: 'some/template' },
viewModel: ...
});
The returned AMD module object can be in any of the forms allowed for viewmodels. So, it can be a string of markup, e.g. fetched using require.js's text plugin:
ko.components.register('my-component', {
template: { require: 'text!path/my-html-file.html' },
viewModel: ...
});
... or any of the other forms described here, though it would be unusual for the others to be useful when fetching templates via AMD.
As well as (or instead of) template and viewModel, your component configuration object can have arbitrary other properties. This configuration object is made available to any custom component loader you may be using.
If your component configuration has a boolean sync property, Knockout uses this to determine whether the component is allowed to be loaded and injected synchronously. The default is false (i.e., forced to be asynchronous). For example,
ko.components.register('my-component', {
viewModel: { ... anything ... },
template: { ... anything ... },
sync: true // Injects synchronously if already loaded, otherwise still async
});
Why is component loading normally forced to be asynchronous?
Normally, Knockout ensures that component loading, and hence component injection, always completes asynchronously, because sometimes it has no choice but to be asynchronous (e.g., because it involves a request to the server). It does this even if a particular component instance could be injected synchronously (e.g., because the component definition was already loaded). This always-asynchronous policy is a matter of consistency, and is a well-established convention inherited from other modern asynchronous JavaScript technologies, such as AMD. The convention is a safe default --- it mitigates potential bugs where a developer might not account for the possibility of a typically-asynchronous process sometimes completing synchronously or vice-versa.
Why would you ever enable synchronous loading?
If you want to change the policy for a particular component, you can specify sync: true on that component's configuration. Then it might load asynchronously on first use, followed by synchronously on all subsequent uses. If you do this, then you need to account for this changeable behavior in any code that waits for components to load.
The benefit of sync: true is primarily that, if you're injecting a long list of copies of a certain component (e.g., inside a foreach binding), and if the component definition is already in memory due to previous usage, then all the new copies may be injected synchronously and cause only a single DOM reflow, which is preferable for performance especially on mobiles.
When you load a viewmodel or template via require declarations, e.g.,
ko.components.register('my-component', {
viewModel: { require: 'some/module/name' },
template: { require: 'text!some-template.html' }
});
...all Knockout does is call require(['some/module/name'], callback) and require(['text!some-template.html'], callback), and uses the asynchronously-returned objects as the viewmodel and template definitions. So,
require API will do. If you want to integrate with a module loader whose API is different, you can implement a custom component loader.require(). So of course Knockout does not know or care about where your module files are loaded from. That's up to your AMD loader and how you've configured it.Knockout does not call require([moduleName], ...) until your component is being instantiated. This is how components get loaded on demand, not up front.
For example, if your component is inside some other element with an if binding (or another control flow binding), then it will not cause the AMD module to be loaded until the if condition is true. Of course, if the AMD module was already loaded (e.g., in a preloaded bundle) then the require call will not trigger any additional HTTP requests, so you can control what is preloaded and what is loaded on demand.
For even better encapsulation, you can package a component into a single self-describing AMD module. Then you can reference a component as simply as:
ko.components.register('my-component', { require: 'some/module' });
Notice that no viewmodel/template pair is specified. The AMD module itself can provide a viewmodel/template pair, using any of the definition formats listed above. For example, the file some/module.js could be declared as:
// AMD module 'some/module.js' encapsulating the configuration for a component
define(['knockout'], function(ko) {
function MyComponentViewModel(params) {
this.personName = ko.observable(params.name);
}
return {
viewModel: MyComponentViewModel,
template: 'The name is <strong data-bind="text: personName"></strong>'
};
});
What tends to be most useful in practice is creating AMD modules that have inline viewmodel classes, and explicitly take AMD dependencies on external template files.
For example, if the following is in a file at path/my-component.js,
// Recommended AMD module pattern for a Knockout component that:
// - Can be referenced with just a single 'require' declaration
// - Can be included in a bundle using the r.js optimizer
define(['knockout', 'text!./my-component.html'], function(ko, htmlString) {
function MyComponentViewModel(params) {
// Set up properties, etc.
}
// Use prototype to declare any public methods
MyComponentViewModel.prototype.doSomething = function() { ... };
// Return component definition
return { viewModel: MyComponentViewModel, template: htmlString };
});
... and the template markup is in the file path/my-component.html, then you have these benefits:
ko.components.register('my-component', { require: 'path/my-component' });path/my-component.js) and a template (path/my-component.html) - which is a very natural arrangement during development.define call, this automatically works with the r.js optimizer or similar bundling tools. The entire component - viewmodel plus template - can therefore trivially be included in a bundle file during a build step.Beginners don't need to know about this, but more advanced developers will want to know why we keep making all these claims about KO automatically tracking dependencies and updating the right parts of the UI...
It's actually very simple and rather lovely. The tracking algorithm goes like this:
So, Knockout doesn't just detect dependencies the first time the evaluator runs - it redetects them every time. This means, for example, that the dependencies can vary dynamically: dependency A could determine whether the computed observable also depend on B or C. Then, it will only be re-evaluated when either A or your current choice of B or C changes. You don't have to declare dependencies: they're determined at runtime from the code's execution.
The other neat trick is that declarative bindings are simply implemented as computed observables. So, if a binding reads the value of an observable, that binding becomes dependent on that observable, which causes that binding to be re-evaluated if the observable changes.
Pure computed observables work slightly differently. For more details, see the documentation for pure computed observables.
Knockout's automatic dependency tracking normally does exactly what you want. But you might sometimes need to control which observables will update your computed observable, especially if the computed observable performs some sort of action, such as making an Ajax request. The peek function lets you access an observable or computed observable without creating a dependency.
In the example below, a computed observable is used to reload an observable named currentPageData using Ajax with data from two other observable properties. The computed observable will update whenever pageIndex changes, but it ignores changes to selectedItem because it is accessed using peek. In this case, the user might want to use the current value of selectedItem only for tracking purposes when a new set of data is loaded.
ko.computed(function() {
var params = {
page: this.pageIndex(),
selected: this.selectedItem.peek()
};
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this);
Note: If you just want to prevent a computed observable from updating too often, see the rateLimit extender.
The ko.ignoreDependencies function is available for scenarios where you want to execute code within a computed that should not contribute to that computed's dependencies. This is often useful in a custom binding when you want to call code that may access observables, but you do not want to re-trigger the binding based on changes to those observables.
ko.ignoreDependencies( callback, callbackTarget, callbackArgs );
Example:
ko.bindingHandlers.myBinding = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.unwrap(valueAccessor());
var value = ko.unwrap(options.value);
var afterUpdateHandler = options.afterUpdate;
// the developer supplied a function to call when this binding updates, but
// we don't really want to track any dependencies that would re-trigger this binding
if (typeof afterUpdateHandler === "function") {
ko.ignoreDependencies(afterUpdateHandler, viewModel, [value, color]);
}
$(element).somePlugin("value", value);
}
}
Computed observables are supposed to map a set of observable inputs into a single observable output. As such, it doesn't make sense to include cycles in your dependency chains. Cycles would not be analogous to recursion; they would be analogous to having two spreadsheet cells that are computed as functions of each other. It would lead to an infinite evaluation loop.
So what does Knockout do if you have a cycle in your dependency graph? It avoids infinite loops by enforcing the following rule: Knockout will not restart evaluation of a computed while it is already evaluating. This is very unlikely to affect your code. It's relevant in two situations: when two computed observables are dependent on each other (possible only if one or both use the deferEvaluation option), or when a computed observable writes to another observable on which it has a dependency (either directly or via a dependency chain). If you need to use one of these patterns and want to entirely avoid the circular dependency, you can use the peek function described above.
Pure computed observables, introduced in Knockout 3.2.0, provide performance and memory benefits over regular computed observables for most applications. This is because a pure computed observable doesn't maintain subscriptions to its dependencies when it has no subscribers itself. This feature:
A pure computed observable automatically switches between two states based on whether it has change subscribers.
Whenever it has no change subscribers, it is sleeping. When entering the sleeping state, it disposes all subscriptions to its dependencies. During this state, it will not subscribe to any observables accessed in the evaluator function (although it does keep track of them). If the computed observable's value is read while it is sleeping, it is automatically re-evaluated if any of its dependencies have changed.
Whenever it has any change subscribers, it is awake and listening. When entering the listening state, it immediately subscribes to any dependencies. In this state, it operates just like a regular computed observable, as described in how dependency tracking works.
We've borrowed the term from pure functions because this feature is generally only applicable for computed observables whose evaluator is a pure function as follows:
The standard method of defining a pure computed observable is to use ko.pureComputed:
this.fullName = ko.pureComputed(function() {
return this.firstName() + " " + this.lastName();
}, this);
Alternatively, you can use the pure option with ko.computed:
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this, { pure: true });
For complete syntax, see the computed observable reference.
You can use the pure feature for any computed observable that follows the pure function guidelines. You'll see the most benefit, though, when it is applied to application designs that involve persistent view models that are used and shared by temporary views and view models. Using pure computed observables in a persistent view model provides computation performance benefits. Using them in temporary view models provides memory management benefits.
In the following example of a simple wizard interface, the fullName pure computed is only bound to the view during the final step and so is only updated when that step is active.
You should not use the pure feature for a computed observable that is meant to perform an action when its dependencies change. Examples include:
Using a computed observable to run a callback based on multiple observables.
ko.computed(function () {
var cleanData = ko.toJS(this);
myDataClient.update(cleanData);
}, this);
In a binding's init function, using a computed observable to update the bound element.
ko.computed({
read: function () {
element.title = ko.unwrap(valueAccessor());
},
disposeWhenNodeIsRemoved: element
});
The reason you shouldn't use a pure computed if the evaluator has important side effects is simply that the evaluator will not run whenever the computed has no active subscribers (and so is sleeping). If it's important for the evaluator to always run when dependencies change, use a regular computed instead.
A pure computed observable notifies an awake event (using its current value) whenever it enters the listening state and notifies an asleep event (using an undefined value) whevener it enter the sleeping state. You won't normally need to know about the internal state of your computed observables. But since the internal state can correspond to whether the computed observable is bound to the view or not, you might use that information to do some view-model initialization or cleanup.
this.someComputedThatWillBeBound = ko.pureComputed(function () {
...
}, this);
this.someComputedThatWillBeBound.subscribe(function () {
// do something when this is bound
}, this, "awake");
this.someComputedThatWillBeBound.subscribe(function () {
// do something when this is un-bound
}, this, "asleep");
(The awake event also applies to normal computed observables created with the deferEvaluation option.)
The following documentation describes how to construct and work with computed observables.
A computed observable can be constructed using one of the following forms:
ko.computed( evaluator [, targetObject, options] ) --- This form supports the most common case of creating a computed observable.
evaluator --- A function that is used to evaluate the computed observable's current value.targetObject --- If given, defines the value of this whenever KO invokes your callback functions. See the section on managing this for more information.options --- An object with further properties for the computed observable. See the full list below.ko.computed( options ) --- This single parameter form for creating a computed observable accepts a JavaScript object with any of the following properties.
read --- Required. A function that is used to evaluate the computed observable's current value.write --- Optional. If given, makes the computed observable writable. This is a function that receives values that other code is trying to write to your computed observable. It's up to you to supply custom logic to handle the incoming values, typically by writing the values to some underlying observable(s).owner --- Optional. If given, defines the value of this whenever KO invokes your read or write callbacks.pure --- Optional. If this option is true, the computed observable will be set up as a pure computed observable. This option is an alternative to the ko.pureComputed constructor.deferEvaluation --- Optional. If this option is true, then the value of the computed observable will not be evaluated until something actually attempts to access its value or manually subscribes to it. By default, a computed observable has its value determined immediately during creation.disposeWhen --- Optional. If given, this function is executed before each re-evaluation to determine if the computed observable should be disposed. A true-ish result will trigger disposal of the computed observable.disposeWhenNodeIsRemoved --- Optional. If given, disposal of the computed observable will be triggered when the specified DOM node is removed by KO. This feature is used to dispose computed observables used in bindings when nodes are removed by the template and control-flow bindings.ko.pureComputed( evaluator [, targetObject] ) --- Constructs a pure computed observable using the given evaluator function and optional object to use for this. Unlike ko.computed, this method doesn't accept an options parameter.
ko.pureComputed( options ) --- Constructs a pure computed observable using an options object. This accepts the read, write, and owner options described above.
A computed observable provides the following functions:
dispose() --- Manually disposes the computed observable, clearing all subscriptions to dependencies. This function is useful if you want to stop a computed observable from being updated or want to clean up memory for a computed observable that has dependencies on observables that won't be cleaned.extend(extenders) --- Applies the given extenders to the computed observable.getDependenciesCount() --- Returns the current number of dependencies of the computed observable.getSubscriptionsCount( [event] ) --- Returns the current number of subscriptions (either from other computed observables or manual subscriptions) of the computed observable. Optionally, pass an event name (like "change") to return just the count of subscriptions for that event.isActive() --- Returns whether the computed observable may be updated in the future. A computed observable is inactive if it has no dependencies.peek() --- Returns the current value of the computed observable without creating a dependency (see the section on peek).subscribe( callback [,callbackTarget, event] ) --- Registers a manual subscription to be notified of changes to the computed observable.During the execution of a computed observable's evaluator function, you can access ko.computedContext to get information about the current computed property. It provides the following functions:
isInitial() --- A function that returns true if called during the first ever evaluation of the current computed observable, or false otherwise. For pure computed observables, isInitial() is always undefined.
getDependenciesCount() --- Returns the number of dependencies of the computed observable detected so far during the current evaluation.
ko.computedContext.getDependenciesCount() is equivalent to calling getDependenciesCount() on the computed observable itself. The reason that it also exists on ko.computedContext is to provide a way of counting the dependencies during the first ever evaluation, before the computed observable has even finished being constructed.Example:
var myComputed = ko.computed(function() {
// ... Omitted: read some data that might be observable ...
// Now let's inspect ko.computedContext
var isFirstEvaluation = ko.computedContext.isInitial(),
dependencyCount = ko.computedContext.getDependenciesCount(),
console.log("Evaluating " + (isFirstEvaluation ? "for the first time" : "again"));
console.log("By now, this computed has " + dependencyCount + " dependencies");
// ... Omitted: return the result ...
});
These facilities are typically useful only in advanced scenarios, for example when your computed observable's primary purpose is to trigger some side-effect during its evaluator, and you want to perform some setup logic only during the first run, or only if it has at least one dependency (and hence might re-evaluate in the future). Most computed properties do not need to care whether they have been evaluated before, or how many dependencies they have.
Beginners may wish to skip this section - writable computed observables are fairly advanced and are not necessary in most situations
Normally, computed observables have a value that is computed from other observables and are therefore read-only. What may seem surprising, then, is that it is possible to make computed observables writable. You just need to supply your own callback function that does something sensible with written values.
You can use a writable computed observable exactly like a regular observable, with your own custom logic intercepting all reads and writes. Just like observables, you can write values to multiple observable or computed observable properties on a model object using chaining syntax. For example, myViewModel.fullName('Joe Smith').age(50).
Writable computed observables are a powerful feature with a wide range of possible uses.
Going back to the classic "first name + last name = full name" example, you can turn things back-to-front: make the fullName computed observable writable, so that the user can directly edit the full name, and their supplied value will be parsed and mapped back to the underlying firstName and lastName observables. In this example, the write callback handles incoming values by splitting the incoming text into "firstName" and "lastName" components, and writing those values back to the underlying observables.
This is the exact opposite of the Hello World example, in that here the first and last names are not editable, but the combined full name is editable.
The preceding view model code demonstrates the single parameter syntax for initializing computed observables. See the computed observable reference for the full list of available options.
When presenting the user with a list of selectable items, it is often useful to include a method to select or deselect all of the items. This can be represented quite intuitively with a boolean value that represents whether all items are selected. When set to true it will select all items, and when set to false it will deselect them.
Sometimes you might want to represent a data point on the screen in a different format than its underlying storage. For example, you might want to store a price as a raw float value, but let the user edit it with a currency symbol and fixed number of decimal places. You can use a writable computed observable to represent the formatted price, mapping incoming values back to the underlying float value:
Now, whenever the user enters a new price, the text box immediately updates to show it formatted with the currency symbol and two decimal places, no matter what format they entered the value in. This gives a great user experience, because the user sees how the software has understood their data entry as a price. They know they can't enter more than two decimal places, because if they try to, the additional decimal places are immediately removed. Similarly, they can't enter negative values, because the write callback strips off any minus sign.
Example 1 showed how a writable computed observable can effectively filter its incoming data by choosing not to write certain values back to the underlying observables if they don't meet some criteria. It ignored full name values that didn't include a space.
Taking this a step further, you could also toggle an isValid flag depending on whether the latest input was satisfactory, and display a message in the UI accordingly. There's an easier way of doing validation (explained below), but first consider the following example, which demonstrates the mechanism:
Now, acceptedNumericValue will only ever contain numeric values, and any other values entered will trigger the appearance of a validation message instead of updating acceptedNumericValue.
Note: For such trivial requirements as validating that an input is numeric, this technique is overkill. It would be far easier just to use jQuery Validation and its number class on the <input> element. Knockout and jQuery Validation work together nicely, as demonstrated on the grid editor example. However, the preceding example demonstrates a more general mechanism for filtering and validating with custom logic to control what kind of user feedback appears, which may be of use if your scenario is more complex than jQuery Validation handles natively.
What if you've got an observable for firstName, and another for lastName, and you want to display the full name? That's where computed observables come in - these are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change.
For example, given the following view model class,
function AppViewModel() {
this.firstName = ko.observable('Bob');
this.lastName = ko.observable('Smith');
}
... you could add a computed observable to return the full name:
function AppViewModel() {
// ... leave firstName and lastName unchanged ...
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
}
Now you could bind UI elements to it, e.g.:
The name is <span data-bind="text: fullName"></span>
... and they will be updated whenever firstName or lastName changes (your evaluator function will be called once each time any of its dependencies change, and whatever value you return will be passed on to the observers such as UI elements or other computed observables).
Beginners may wish to skip this section - as long as you follow the same coding patterns as the examples, you won't need to know or care about it!
In case you're wondering what the second parameter to ko.computed is (the bit where we passed this in the preceding code), that defines the value of this when evaluating the computed observable. Without passing it in, it would not have been possible to refer to this.firstName() or this.lastName(). Experienced JavaScript coders will regard this as obvious, but if you're still getting to know JavaScript it might seem strange. (Languages like C# and Java never expect the programmer to set a value for this, but JavaScript does, because its functions themselves aren't part of any object by default.)
There's a popular convention for avoiding the need to track this altogether: if your viewmodel's constructor copies a reference to this into a different variable (traditionally called self), you can then use self throughout your viewmodel and don't have to worry about it being redefined to refer to something else. For example:
function AppViewModel() {
var self = this;
self.firstName = ko.observable('Bob');
self.lastName = ko.observable('Smith');
self.fullName = ko.computed(function() {
return self.firstName() + " " + self.lastName();
});
}
Because self is captured in the function's closure, it remains available and consistent in any nested functions, such as the ko.computed evaluator. This convention is even more useful when it comes to event handlers, as you'll see in many of the live examples.
Of course, you can create whole chains of computed observables if you wish. For example, you might have:
items representing a set of itemsselectedIndexes storing which item indexes have been 'selected' by the userselectedItems that returns an array of item objects corresponding to the selected indexestrue or false depending on whether any of selectedItems has some property (like being new or being unsaved). Some UI element, like a button, might be enabled or disabled based on this value.Then, changes to items or selectedIndexes will ripple through the chain of computed observables, which in turn updates any UI bound to them. Very tidy and elegant.
When a computed observable returns a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in notify extender to ensure that a computed observable's subscribers are always notified on an update, even if the value is the same. You would apply the extender like this:
myViewModel.fullName = ko.computed(function() {
return myViewModel.firstName() + " " + myViewModel.lastName();
}).extend({ notify: 'always' });
Normally, a computed observable updates and notifies its subscribers immediately, as soon as its dependencies change. But if a computed observable has many dependencies or involves expensive updates, you may get better performance by limiting or delaying the computed observable's updates and notifications. This is accomplished using the rateLimit extender like this:
// Ensure updates no more than once per 50-millisecond period
myViewModel.fullName.extend({ rateLimit: 50 });
Beginners may wish to skip this section - writeable computed observables are fairly advanced and are not necessary in most situations
As you've learned, computed observables have a value that is computed from other observables. In that sense, computed observables are normally read-only. What may seem surprising, then, is that it is possible to make computed observables writeable. You just need to supply your own callback function that does something sensible with written values.
You can then use your writeable computed observable exactly like a regular observable, with your own custom logic intercepting all reads and writes. This is a powerful feature with a wide range of possible uses. Just like observables, you can write values to multiple observable or computed observable properties on a model object using chaining syntax. For example, myViewModel.fullName('Joe Smith').age(50).
Going back to the classic "first name + last name = full name" example, you can turn things back-to-front: make the fullName computed observable writeable, so that the user can directly edit the full name, and their supplied value will be parsed and mapped back to the underlying firstName and lastName observables:
function MyViewModel() {
this.firstName = ko.observable('Planet');
this.lastName = ko.observable('Earth');
this.fullName = ko.computed({
read: function () {
return this.firstName() + " " + this.lastName();
},
write: function (value) {
var lastSpacePos = value.lastIndexOf(" ");
if (lastSpacePos > 0) { // Ignore values with no space character
this.firstName(value.substring(0, lastSpacePos)); // Update "firstName"
this.lastName(value.substring(lastSpacePos + 1)); // Update "lastName"
}
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
In this example, the write callback handles incoming values by splitting the incoming text into "firstName" and "lastName" components, and writing those values back to the underlying observables. You can bind this view model to your DOM in the obvious way, as follows:
<p>First name: <span data-bind="text: firstName"></span></p>
<p>Last name: <span data-bind="text: lastName"></span></p>
<h2>Hello, <input data-bind="value: fullName"/>!</h2>
This is the exact opposite of the Hello World example, in that here the first and last names are not editable, but the combined full name is editable.
The preceding view model code demonstrates the single parameter syntax for initializing computed observables. See the computed observable reference below for the full list of available options.
Sometimes you might want to represent a data point on the screen in a different format from its underlying storage. For example, you might want to store a price as a raw float value, but let the user edit it with a currency symbol and fixed number of decimal places. You can use a writeable computed observable to represent the formatted price, mapping incoming values back to the underlying float value:
function MyViewModel() {
this.price = ko.observable(25.99);
this.formattedPrice = ko.computed({
read: function () {
return '$' + this.price().toFixed(2);
},
write: function (value) {
// Strip out unwanted characters, parse as float, then write the raw data back to the underlying "price" observable
value = parseFloat(value.replace(/[^\.\d]/g, ""));
this.price(isNaN(value) ? 0 : value); // Write to underlying storage
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
It's trivial to bind the formatted price to a text box:
<p>Enter bid price: <input data-bind="value: formattedPrice"/></p>
Now, whenever the user enters a new price, the text box immediately updates to show it formatted with the currency symbol and two decimal places, no matter what format they entered the value in. This gives a great user experience, because the user sees how the software has understood their data entry as a price. They know they can't enter more than two decimal places, because if they try to, the additional decimal places are immediately removed. Similarly, they can't enter negative values, because the write callback strips off any minus sign.
Example 1 showed how a writeable computed observable can effectively filter its incoming data by choosing not to write certain values back to the underlying observables if they don't meet some criteria. It ignored full name values that didn't include a space.
Taking this a step further, you could also toggle an isValid flag depending on whether the latest input was satisfactory, and display a message in the UI accordingly. There's an easier way of doing validation (explained below), but first consider the following view model, which demonstrates the mechanism:
function MyViewModel() {
this.acceptedNumericValue = ko.observable(123);
this.lastInputWasValid = ko.observable(true);
this.attemptedValue = ko.computed({
read: this.acceptedNumericValue,
write: function (value) {
if (isNaN(value))
this.lastInputWasValid(false);
else {
this.lastInputWasValid(true);
this.acceptedNumericValue(value); // Write to underlying storage
}
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
... with the following DOM elements:
<p>Enter a numeric value: <input data-bind="value: attemptedValue"/></p>
<div data-bind="visible: !lastInputWasValid()">That's not a number!</div>
Now, acceptedNumericValue will only ever contain numeric values, and any other values entered will trigger the appearance of a validation message instead of updating acceptedNumericValue.
Note: For such trivial requirements as validating that an input is numeric, this technique is overkill. It would be far easier just to use jQuery Validation and its number class on the <input> element. Knockout and jQuery Validation work together nicely, as demonstrated on the grid editor example. However, the preceding example demonstrates a more general mechanism for filtering and validating with custom logic to control what kind of user feedback appears, which may be of use if your scenario is more complex than jQuery Validation handles natively.
Beginners don't need to know about this, but more advanced developers will want to know why we keep making all these claims about KO automatically tracking dependencies and updating the right parts of the UI...
It's actually very simple and rather lovely. The tracking algorithm goes like this:
So, KO doesn't just detect your dependencies the first time your evaluator runs - it redetects them every time. This means, for example, that your dependencies can vary dynamically: dependency A could determine whether you also depend on B or C. Then, you'll only be re-evaluated when either A or your current choice of B or C changes. You don't have to declare dependencies: they're inferred at runtime from the code's execution.
The other neat trick is that declarative bindings are simply implemented as computed observables. So, if a binding reads the value of an observable, that binding becomes dependent on that observable, which causes that binding to be re-evaluated if the observable changes.
Knockout's automatic dependency tracking normally does exactly what you want. But you might sometimes need to control which observables will update your computed observable, especially if the computed observable performs some sort of action, such as making an Ajax request. The peek function lets you access an observable or computed observable without creating a dependency.
In the example below, a computed observable is used to reload an observable named currentPageData using Ajax with data from two other observable properties. The computed observable will update whenever pageIndex changes, but it ignores changes to selectedItem because it is accessed using peek. In this case, the user might want to use the current value of selectedItem only for tracking purposes when a new set of data is loaded.
ko.computed(function() {
var params = {
page: this.pageIndex(),
selected: this.selectedItem.peek()
};
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this);
Note: If you just want to prevent a computed observable from updating too often, see the rateLimit extender.
Computed observables are supposed to map a set of observable inputs into a single observable output. As such, it doesn't make sense to include cycles in your dependency chains. Cycles would not be analogous to recursion; they would be analogous to having two spreadsheet cells that are computed as functions of each other. It would lead to an infinite evaluation loop.
So what does Knockout do if you have a cycle in your dependency graph? It avoids infinite loops by enforcing the following rule: Knockout will not restart evaluation of a computed while it is already evaluating. This is very unlikely to affect your code. It's relevant in two situations: when two computed observables are dependent on each other (possible only if one or both use the deferEvaluation option), or when a computed observable writes to another observable on which it has a dependency (either directly or via a dependency chain). If you need to use one of these patterns and want to entirely avoid the circular dependency, you can use the peek function described above.
In some scenarios, it is useful to programmatically determine if you are dealing with a computed observable. Knockout provides a utility function, ko.isComputed to help with this situation. For example, you might want to exclude computed observables from data that you are sending back to the server.
for (var prop in myObject) {
if (myObject.hasOwnProperty(prop) && !ko.isComputed(myObject[prop])) {
result[prop] = myObject[prop];
}
}
Additionally, Knockout provides similar functions that can operate on observables and computed observables:
ko.isObservable - returns true for observables, observable arrays, and all computed observables.ko.isWriteableObservable - returns true for observable, observable arrays, and writeable computed observables.The following documentation describes how to construct and work with computed observables.
A computed observable can be constructed using one of the following forms:
ko.computed( evaluator [, targetObject, options] ) --- This form supports the most common case of creating a computed observable.
evaluator --- A function that is used to evaluate the computed observable's current value.targetObject --- If given, defines the value of this whenever KO invokes your callback functions. See the section on managing this for more information.options --- An object with further properties for the computed observable. See the full list below.ko.computed( options ) --- This single parameter form for creating a computed observable accepts a JavaScript object with any of the following properties.
read --- Required. A function that is used to evaluate the computed observable's current value.write --- Optional. If given, makes the computed observable writeable. This is a function that receives values that other code is trying to write to your computed observable. It's up to you to supply custom logic to handle the incoming values, typically by writing the values to some underlying observable(s).owner --- Optional. If given, defines the value of this whenever KO invokes your read or write callbacks.deferEvaluation --- Optional. If this option is true, then the value of the computed observable will not be evaluated until something actually attempts to access its value or manually subscribes to it. By default, a computed observable has its value determined immediately during creation.disposeWhen --- Optional. If given, this function is executed on each re-evaluation to determine if the computed observable should be disposed. A true-ish result will trigger disposal of the computed observable.disposeWhenNodeIsRemoved --- Optional. If given, disposal of the computed observable will be triggered when the specified DOM node is removed by KO. This feature is used to dispose computed observables used in bindings when nodes are removed by the template and control-flow bindings.A computed observable provides the following functions:
dispose() --- Manually disposes the computed observable, clearing all subscriptions to dependencies. This function is useful if you want to stop a computed observable from being updated or want to clean up memory for a computed observable that has dependencies on observables that won't be cleaned.extend(extenders) --- Applies the given extenders to the computed observable.getDependenciesCount() --- Returns the current number of dependencies of the computed observable.getSubscriptionsCount() --- Returns the current number of subscriptions (either from other computed observables or manual subscriptions) of the computed observable.isActive() --- Returns whether the computed observable may be updated in the future. A computed observable is inactive if it has no dependencies.peek() --- Returns the current value of the computed observable without creating a dependency (see the section above on peek).subscribe( callback [,callbackTarget, event] ) --- Registers a manual subscription to be notified of changes to the computed observable.During the execution of a computed observable's evaluator function, you can access ko.computedContext to get information about the current computed property. It provides the following functions:
isInitial() --- A function that returns true if called during the first ever evaluation of the current computed observable, or false otherwise.
getDependenciesCount() --- Returns the number of dependencies of the computed observable detected so far during the current evaluation.
ko.computedContext.getDependenciesCount() is equivalent to calling getDependenciesCount() on the computed observable itself. The reason that it also exists on ko.computedContext is to provide a way of counting the dependencies during the first ever evaluation, before the computed observable has even finished being constructed.Example:
var myComputed = ko.computed(function() {
// ... Omitted: read some data that might be observable ...
// Now let's inspect ko.computedContext
var isFirstEvaluation = ko.computedContext.isInitial(),
dependencyCount = ko.computedContext.getDependenciesCount(),
console.log("Evaluating " + (isFirstEvaluation ? "for the first time" : "again"));
console.log("By now, this computed has " + dependencyCount + " dependencies");
// ... Omitted: return the result ...
});
These facilities are typically useful only in advanced scenarios, for example when your computed observable's primary purpose is to trigger some side-effect during its evaluator, and you want to perform some setup logic only during the first run, or only if it has at least one dependency (and hence might re-evaluate in the future). Most computed properties do not need to care whether they have been evaluated before, or how many dependencies they have.
Note: Computed observables were once called "dependent observables", but have since been renamed i.e. ko.dependentObservable === ko.computed
The css binding adds or removes one or more named CSS classes to the associated DOM element. This is useful, for example, to highlight some value in red if it becomes negative.
(Note: If you don't want to apply a CSS class but instead want to assign a style attribute value directly, see the style binding.)
<div data-bind="css: { profitWarning: currentProfit() < 0 }">
Profit Information
</div>
```javascript
var viewModel = {
currentProfit: ko.observable(150000) // Positive value, so initially we don't apply the "profitWarning" class
};
viewModel.currentProfit(-50); // Causes the "profitWarning" class to be applied
This will apply the CSS class profitWarning whenever the currentProfit value dips below zero, and remove that class whenever it goes above zero.
<div data-bind="css: profitStatus">
Profit Information
</div>
var viewModel = {
currentProfit: ko.observable(150000)
};
// Evalutes to a positive value, so initially we apply the "profitPositive" class
viewModel.profitStatus = ko.computed(function() {
return this.currentProfit() < 0 ? "profitWarning" : "profitPositive";
}, viewModel);
// Causes the "profitPositive" class to be removed and "profitWarning" class to be added
viewModel.currentProfit(-50);
This will apply the CSS class profitPositive when the currentProfit value is positive, otherwise it will apply the profitWarning CSS class.
Main parameter
If you are using static CSS class names, then you can pass a JavaScript object in which the property names are your CSS classes, and their values evaluate to true or false according to whether the class should currently be applied.
You can set multiple CSS classes at once. For example, if your view model has a property called isSevere,
<div data-bind="css: { profitWarning: currentProfit() < 0, majorHighlight: isSevere }">
You can even set multiple CSS classes based on the same condition by wrapping the names in quotes like:
<div data-bind="css: { profitWarning: currentProfit() < 0, 'major highlight': isSevere }">
Non-boolean values are interpreted loosely as boolean. For example, 0 and null are treated as false, whereas 21 and non-null objects are treated as true.
If your parameter references an observable value, the binding will add or remove the CSS class whenever the observable value changes. If the parameter doesn't reference an observable value, it will only add or remove the class once and will not do so again later.
If you want to use dynamic CSS class names, then you can pass a string that corresponds to the CSS class or classes that you want to add to the element. If the parameter references an observable value, then the binding will remove any previously added classes and add the class or classes corresponding to the observable's new value.
As usual, you can use arbitrary JavaScript expressions or functions as parameter values. KO will evaluate them and use the resulting values to determine the appropriate CSS classes to add or remove.
Additional parameters
If you want to apply the CSS class my-class, you can't write this:
<div data-bind="css: { my-class: someValue }">...</div>
... because my-class isn't a legal identifier name at that point. The solution is simple: just wrap the identifier name in quotes so that it becomes a string literal, which is legal in a JavaScript object literal. For example,
<div data-bind="css: { 'my-class': someValue }">...</div>
Note: Creating custom bindings that control descendant binding is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.
By default, bindings only affect the element to which they are applied. But what if you want to affect all descendant elements too? This is possible. Your binding can tell Knockout not to bind descendants at all, and then your custom binding can do whatever it likes to bind them in a different way.
To do this, simply return { controlsDescendantBindings: true } from your binding's init function.
For a very simple example, here's a custom binding called allowBindings that allows descendant bindings to be applied only if its value is true. If the value is false, then allowBindings tells Knockout that it is responsible for descendant bindings so they won't be bound as usual.
ko.bindingHandlers.allowBindings = {
init: function(elem, valueAccessor) {
// Let bindings proceed as normal *only if* my value is false
var shouldAllowBindings = ko.unwrap(valueAccessor());
return { controlsDescendantBindings: !shouldAllowBindings };
}
};
To see this take effect, here's a sample usage:
<div data-bind="allowBindings: true">
<!-- This will display Replacement, because bindings are applied -->
<div data-bind="text: 'Replacement'">Original</div>
</div>
<div data-bind="allowBindings: false">
<!-- This will display Original, because bindings are not applied -->
<div data-bind="text: 'Replacement'">Original</div>
</div>
Normally, bindings that use controlsDescendantBindings will also call ko.applyBindingsToDescendants(someBindingContext, element) to apply the descendant bindings against some modified binding context. For example, you could have a binding called withProperties that attaches some extra properties to the binding context that will then be available to all descendant bindings:
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Make a modified binding context, with a extra properties, and apply it to descendant elements
var innerBindingContext = bindingContext.extend(valueAccessor);
ko.applyBindingsToDescendants(innerBindingContext, element);
// Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
return { controlsDescendantBindings: true };
}
};
As you can see, binding contexts have an extend function that produces a clone with extra properties. The extend function accepts either an object with the properties to copy or a function that returns such an object. The function syntax is preferred so that future changes in the binding value are always updated in the binding context. This process doesn't affect the original binding context, so there is no danger of affecting sibling-level elements - it will only affect descendants.
Here's an example of using the above custom binding:
<div data-bind="withProperties: { emotion: 'happy' }">
Today I feel <span data-bind="text: emotion"></span>. <!-- Displays: happy -->
</div>
<div data-bind="withProperties: { emotion: 'whimsical' }">
Today I feel <span data-bind="text: emotion"></span>. <!-- Displays: whimsical -->
</div>
Bindings such as with and foreach create extra levels in the binding context hierarchy. This means that their descendants can access data at outer levels by using $parent, $parents, $root, or $parentContext.
If you want to do this in custom bindings, then instead of using bindingContext.extend(), use bindingContext.createChildContext(someData). This returns a new binding context whose viewmodel is someData and whose $parentContext is bindingContext. If you want, you can then extend the child context with extra properties using ko.utils.extend. For example,
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Make a modified binding context, with a extra properties, and apply it to descendant elements
var childBindingContext = bindingContext.createChildContext(
bindingContext.$rawData,
null, // Optionally, pass a string here as an alias for the data item in descendant contexts
function(context) {
ko.utils.extend(context, valueAccessor());
});
ko.applyBindingsToDescendants(childBindingContext, element);
// Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
return { controlsDescendantBindings: true };
}
};
This updated withProperties binding could now be used in a nested way, with each level of nesting able to access the parent level via $parentContext:
<div data-bind="withProperties: { displayMode: 'twoColumn' }">
The outer display mode is <span data-bind="text: displayMode"></span>.
<div data-bind="withProperties: { displayMode: 'doubleWidth' }">
The inner display mode is <span data-bind="text: displayMode"></span>, but I haven't forgotten
that the outer display mode is <span data-bind="text: $parentContext.displayMode"></span>.
</div>
</div>
By modifying binding contexts and controlling descendant bindings, you have a powerful and advanced tool to create custom binding mechanisms of your own.
In a typical Knockout application, DOM elements are dynamically added and removed, for example using the template binding or via control-flow bindings (if, ifnot, with, and foreach). When creating a custom binding, it is often desirable to add clean-up logic that runs when an element associated with your custom binding is removed by Knockout.
To register a function to run when a node is removed, you can call ko.utils.domNodeDisposal.addDisposeCallback(node, callback). As an example, suppose you create a custom binding to instantiate a widget. When the element with the binding is removed, you may want to call the destroy method of the widget:
ko.bindingHandlers.myWidget = {
init: function(element, valueAccessor) {
var options = ko.unwrap(valueAccessor()),
$el = $(element);
$el.myWidget(options);
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
// This will be called when the element is removed by Knockout or
// if some other part of your code calls ko.removeNode(element)
$el.myWidget("destroy");
});
}
};
When removing an element, Knockout runs logic to clean up any data associated with the element. As part of this logic, Knockout calls jQuery's cleanData method if jQuery is loaded in your page. In advanced scenarios, you may want to prevent or customize how this data is removed in your application. Knockout exposes a function, ko.utils.domNodeDisposal.cleanExternalData(node), that can be overridden to support custom logic. For example, to prevent cleanData from being called, an empty function could be used to replace the standard cleanExternalData implementation:
ko.utils.domNodeDisposal.cleanExternalData = function () {
// Do nothing. Now any jQuery data associated with elements will
// not be cleaned up when the elements are removed from the DOM.
};
Note: Creating custom bindings that support virtual elements is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.
Knockout's control flow bindings (e.g., if and foreach) can be applied not only to regular DOM elements, but also to "virtual" DOM elements defined by a special comment-based syntax. For example:
<ul>
<li class="heading">My heading</li>
<!-- ko foreach: items -->
<li data-bind="text: $data"></li>
<!-- /ko -->
</ul>
Custom bindings can work with virtual elements too, but to enable this, you must explicitly tell Knockout that your binding understands virtual elements, by using the ko.virtualElements.allowedBindings API.
To get started, here's a custom binding that randomises the order of DOM nodes:
ko.bindingHandlers.randomOrder = {
init: function(elem, valueAccessor) {
// Pull out each of the child elements into an array
var childElems = [];
while(elem.firstChild)
childElems.push(elem.removeChild(elem.firstChild));
// Put them back in a random order
while(childElems.length) {
var randomIndex = Math.floor(Math.random() * childElems.length),
chosenChild = childElems.splice(randomIndex, 1);
elem.appendChild(chosenChild[0]);
}
}
};
This works nicely with regular DOM elements. The following elements will be shuffled into a random order:
<div data-bind="randomOrder: true">
<div>First</div>
<div>Second</div>
<div>Third</div>
</div>
However, it does not work with virtual elements. If you try the following:
<!-- ko randomOrder: true -->
<div>First</div>
<div>Second</div>
<div>Third</div>
<!-- /ko -->
... then you'll get the error The binding 'randomOrder' cannot be used with virtual elements. Let's fix this. To make randomOrder usable with virtual elements, start by telling Knockout to allow it. Add the following:
ko.virtualElements.allowedBindings.randomOrder = true;
Now there won't be an error. However, it still won't work properly, because our randomOrder binding is coded using normal DOM API calls (firstChild, appendChild, etc.) which don't understand virtual elements. This is the reason why KO requires you to explicitly opt in to virtual element support: unless your custom binding is coded using virtual element APIs, it's not going to work properly!
Let's update the code for randomOrder, this time using KO's virtual element APIs:
ko.bindingHandlers.randomOrder = {
init: function(elem, valueAccessor) {
// Build an array of child elements
var child = ko.virtualElements.firstChild(elem),
childElems = [];
while (child) {
childElems.push(child);
child = ko.virtualElements.nextSibling(child);
}
// Remove them all, then put them back in a random order
ko.virtualElements.emptyNode(elem);
while(childElems.length) {
var randomIndex = Math.floor(Math.random() * childElems.length),
chosenChild = childElems.splice(randomIndex, 1);
ko.virtualElements.prepend(elem, chosenChild[0]);
}
}
};
Notice how, instead of using APIs like domElement.firstChild, we're now using ko.virtualElements.firstChild(domOrVirtualElement). The randomOrder binding will now correctly work with virtual elements, e.g., <!-- ko randomOrder: true -->...<!-- /ko -->.
Also, randomOrder will still work with regular DOM elements, because all of the ko.virtualElements APIs are backwardly compatible with regular DOM elements.
In some browsers you must be careful about virtual elements inside <tbody> and <thead> tags, since they may be "hoisted" out. For example:
<table>
<!-- foreach: list -->
<tr><td> ... </td></tr>
<!-- /foreach -->
</table>
may be interpreted by the browser as:
<table>
<!-- foreach: list -->
<!-- /foreach -->
<tbody>
<tr><td> ... </td></tr>
</tbody>
</table>
Be mindful of using virtual elements inside tables.
For more information on this caveat, see issue #1759.
Knockout provides the following functions for working with virtual elements.
ko.virtualElements.allowedBindings
An object whose keys determine which bindings are usable with virtual elements. Set ko.virtualElements.allowedBindings.mySuperBinding = true to allow mySuperBinding to be used with virtual elements.
ko.virtualElements.emptyNode(containerElem)
Removes all child nodes from the real or virtual element containerElem (cleaning away any data associated with them to avoid memory leaks).
ko.virtualElements.firstChild(containerElem)
Returns the first child of the real or virtual element containerElem, or null if there are no children.
ko.virtualElements.insertAfter(containerElem, nodeToInsert, insertAfter)
Inserts nodeToInsert as a child of the real or virtual element containerElem, positioned immediately after insertAfter (where insertAfter must be a child of containerElem).
ko.virtualElements.nextSibling(node)
Returns the sibling node that follows node in its real or virtual parent element, or null if there is no following sibling.
ko.virtualElements.prepend(containerElem, nodeToPrepend)
Inserts nodeToPrepend as the first child of the real or virtual element containerElem.
ko.virtualElements.setDomNodeChildren(containerElem, arrayOfNodes)
Removes all child nodes from the real or virtual element containerElem (in the process, cleaning away any data associated with them to avoid memory leaks), and then inserts all of the nodes from arrayOfNodes as its new children.
Notice that this is not intended to be a complete replacement to the full set of regular DOM APIs. Knockout provides only a minimal set of virtual element APIs to make it possible to perform the kinds of transformations needed when implementing control flow bindings.
You're not limited to using the built-in bindings like click, value, and so on --- you can create your own ones. This is how to control how observables interact with DOM elements, and gives you a lot of flexibility to encapsulate sophisticated behaviors in an easy-to-reuse way.
For example, you can create interactive components like grids, tabsets, and so on, in the form of custom bindings (see the grid example).
To register a binding, add it as a subproperty of ko.bindingHandlers:
ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called once when the binding is first applied to an element,
// and again whenever the associated observable changes value.
// Update the DOM element based on the supplied values here.
}
};
... and then you can use it on any number of DOM elements:
<div data-bind="yourBindingName: someValue"> </div>
Note: you don't actually have to provide both init and update callbacks --- you can just provide one or the other if that's all you need.
Whenever the associated observable changes, KO will call your update callback, passing the following parameters:
element --- The DOM element involved in this bindingvalueAccessor --- A JavaScript function that you can call to get the current model property that is involved in this binding. Call this without passing any parameters (i.e., call valueAccessor()) to get the current model property value. To easily accept both observable and plain values, call ko.unwrap on the returned value.allBindings --- A JavaScript object that you can use to access all the model values bound to this DOM element. Call allBindings.get('name') to retrieve the value of the name binding (returns undefined if the binding doesn't exist); or allBindings.has('name') to determine if the name binding is present for the current element.viewModel --- This parameter is deprecated in Knockout 3.x. Use bindingContext.$data or bindingContext.$rawData to access the view model instead.bindingContext --- An object that holds the binding context available to this element's bindings. This object includes special properties including $parent, $parents, and $root that can be used to access data that is bound against ancestors of this context.For example, you might have been controlling an element's visibility using the visible binding, but now you want to go a step further and animate the transition. You want elements to slide into and out of existence according to the value of an observable. You can do this by writing a custom binding that calls jQuery's slideUp/slideDown functions:
ko.bindingHandlers.slideVisible = {
update: function(element, valueAccessor, allBindings) {
// First get the latest data that we're bound to
var value = valueAccessor();
// Next, whether or not the supplied model property is observable, get its current value
var valueUnwrapped = ko.unwrap(value);
// Grab some more data from another binding property
var duration = allBindings.get('slideDuration') || 400; // 400ms is default duration unless otherwise specified
// Now manipulate the DOM element
if (valueUnwrapped == true)
$(element).slideDown(duration); // Make the element visible
else
$(element).slideUp(duration); // Make the element invisible
}
};
Now you can use this binding as follows:
<div data-bind="slideVisible: giftWrap, slideDuration:600">You have selected the option</div>
<label><input type="checkbox" data-bind="checked: giftWrap" /> Gift wrap</label>
var viewModel = {
giftWrap: ko.observable(true)
};
ko.applyBindings(viewModel);
Of course, this is a lot of code at first glance, but once you've created your custom bindings they can very easily be reused in many places.
Knockout will call your init function once for each DOM element that you use the binding on. There are two main uses for init:
KO will pass exactly the same set of parameters that it passes to the update callback.
Continuing the previous example, you might want slideVisible to set the element to be instantly visible or invisible when the page first appears (without any animated slide), so that the animation only runs when the user changes the model state. You could do that as follows:
ko.bindingHandlers.slideVisible = {
init: function(element, valueAccessor) {
var value = ko.unwrap(valueAccessor()); // Get the current value of the current property we're bound to
$(element).toggle(value); // jQuery will hide/show the element depending on whether "value" or true or false
},
update: function(element, valueAccessor, allBindings) {
// Leave as before
}
};
This means that if giftWrap was defined with the initial state false (i.e., giftWrap: ko.observable(false)) then the associated DIV would initially be hidden, and then would slide into view when the user later checks the box.
You've already seen how to use update so that, when an observable changes, you can update an associated DOM element. But what about events in the other direction? When the user performs some action on a DOM element, you might want to updated an associated observable.
You can use the init callback as a place to register an event handler that will cause changes to the associated observable. For example,
ko.bindingHandlers.hasFocus = {
init: function(element, valueAccessor) {
$(element).focus(function() {
var value = valueAccessor();
value(true);
});
$(element).blur(function() {
var value = valueAccessor();
value(false);
});
},
update: function(element, valueAccessor) {
var value = valueAccessor();
if (ko.unwrap(value))
element.focus();
else
element.blur();
}
};
Now you can both read and write the "focusedness" of an element by binding it to an observable:
<p>Name: <input data-bind="hasFocus: editingName" /></p>
<!-- Showing that we can both read and write the focus state -->
<div data-bind="visible: editingName">You're editing the name</div>
<button data-bind="enable: !editingName(), click:function() { editingName(true) }">Edit name</button>
var viewModel = {
editingName: ko.observable()
};
ko.applyBindings(viewModel);
If you want a custom binding to be usable with Knockout's virtual elements syntax, e.g.:
<!-- ko mybinding: somedata --> ... <!-- /ko -->
... then see the documentation for virtual elements.
The disable binding causes the associated DOM element to be disabled only when the parameter value is true. This is useful with form elements like input, select, and textarea.
This is the mirror image of the enable binding. For more information, see documentation for the enable binding, because disable works in exactly the same way except that it negates whatever parameter you pass to it.
The enable binding causes the associated DOM element to be enabled only when the parameter value is true. This is useful with form elements like input, select, and textarea.
In this example, the "Your cellphone number" text box will initially be disabled. It will be enabled only when the user checks the box labelled "I have a cellphone".
Main parameter
A value that controls whether or not the associated DOM element should be enabled.
Non-boolean values are interpreted loosely as boolean. For example, 0 and null are treated as false, whereas 21 and non-null objects are treated as true.
If your parameter references an observable value, the binding will update the enabled/disabled state whenever the observable value changes. If the parameter doesn't reference an observable value, it will only set the state once and will not do so again later.
Additional parameters
You're not limited to referencing variables - you can reference arbitrary expressions to control an element's enabledness. For example,
<button data-bind="enable: parseAreaCode(viewModel.cellphoneNumber()) != '555'">
Do something
</button>
None, other than the core Knockout library.
The event binding allows you to add an event handler for a specified event so that your chosen JavaScript function will be invoked when that event is triggered for the associated DOM element. This can be used to bind to any event, such as keypress, mouseover or mouseout.
<div>
<div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }">
Mouse over me
</div>
<div data-bind="visible: detailsEnabled">
Details
</div>
</div>
var viewModel = {
detailsEnabled: ko.observable(false),
enableDetails: function() {
this.detailsEnabled(true);
},
disableDetails: function() {
this.detailsEnabled(false);
}
};
ko.applyBindings(viewModel);
Now, moving your mouse pointer on or off of the first element will invoke methods on the view model to toggle the detailsEnabled observable. The second element reacts to changes to the value of detailsEnabled by either showing or hiding itself.
Main parameter
You should pass a JavaScript object in which the property names correspond to event names, and the values correspond to the function that you want to bind to the event.
You can reference any JavaScript function - it doesn't have to be a function on your view model. You can reference a function on any object by writing event { mouseover: someObject.someFunction }.
Additional parameters
When calling your handler, Knockout will supply the current model value as the first parameter. This is particularly useful if you're rendering some UI for each item in a collection, and you need to know which item the event refers to. For example,
<ul data-bind="foreach: places">
<li data-bind="text: $data, event: { mouseover: $parent.logMouseOver }"> </li>
</ul>
<p>You seem to be interested in: <span data-bind="text: lastInterest"> </span></p>
function MyViewModel() {
var self = this;
self.lastInterest = ko.observable();
self.places = ko.observableArray(['London', 'Paris', 'Tokyo']);
// The current item will be passed as the first parameter, so we know which place was hovered over
self.logMouseOver = function(place) {
self.lastInterest(place);
}
}
ko.applyBindings(new MyViewModel());
Two points to note about this example:
foreach or a with block, but your handler function
is on the root viewmodel or some other parent context, you'll need to use a prefix such as $parent or $root to locate the
handler function.self (or some other variable) as an alias for this. Doing so avoids any problems
with this being redefined to mean something else in event handlers or Ajax request callbacks.In some scenarios, you may need to access the DOM event object associated with your event. Knockout will pass the event as the second parameter to your function, as in this example:
<div data-bind="event: { mouseover: myFunction }">
Mouse over me
</div>
var viewModel = {
myFunction: function(data, event) {
if (event.shiftKey) {
//do something different when user has shift key down
} else {
//do normal action
}
}
};
ko.applyBindings(viewModel);
If you need to pass more parameters, one way to do it is by wrapping your handler in a function literal that takes in a parameter, as in this example:
<div data-bind="event: { mouseover: function(data, event) { myFunction('param1', 'param2', data, event) } }">
Mouse over me
</div>
Now, KO will pass the event to your function literal, which is then available to be passed to your handler.
Alternatively, if you prefer to avoid the function literal in your view, you can use the bind function, which attaches specific parameter values to a function reference:
<button data-bind="event: { mouseover: myFunction.bind($data, 'param1', 'param2') }">
Click me
</button>
By default, Knockout will prevent the event from taking any default action. For example if you use the event binding to capture the keypress event of an input tag, the browser will only call your handler function and will not add the value of the key to the input element's value. A more common example is using the click binding, which internally uses this binding, where your handler function will be called, but the browser will not navigate to the link's href. This is a useful default because when you use the click binding, it's normally because you're using the link as part of a UI that manipulates your view model, not as a regular hyperlink to another web page.
However, if you do want to let the default action proceed, just return true from your event handler function.
By default, Knockout will allow the event to continue to bubble up to any higher level event handlers. For example, if your element is handling a mouseover event and a parent of the element also handles that same event, then the event handler for both elements will be triggered. If necessary, you can prevent the event from bubbling by including an additional binding that is named youreventBubble and passing false to it, as in this example:
<div data-bind="event: { mouseover: myDivHandler }">
<button data-bind="event: { mouseover: myButtonHandler }, mouseoverBubble: false">
Click me
</button>
</div>
Normally, in this case myButtonHandler would be called first, then the event would bubble up to myDivHandler. However, the mouseoverBubble binding that we added with a value of false prevents the event from making it past myButtonHandler.
Knockout observables provide the basic features necessary to support reading/writing values and notifying subscribers when that value changes. In some cases, though, you may wish to add additional functionality to an observable. This might include adding additional properties to the observable or intercepting writes by placing a writeable computed observable in front of the observable. Knockout extenders provide an easy and flexible way to do this type of augmentation to an observable.
Creating an extender involves adding a function to the ko.extenders object. The function takes in the observable itself as the first argument and any options in the second argument. It can then either return the observable or return something new like a computed observable that uses the original observable in some way.
This simple logChange extender subscribes to the observable and uses the console to write any changes along with a configurable message.
ko.extenders.logChange = function(target, option) {
target.subscribe(function(newValue) {
console.log(option + ": " + newValue);
});
return target;
};
You would use this extender by calling the extend function of an observable and passing an object that contains a logChange property.
this.firstName = ko.observable("Bob").extend({logChange: "first name"});
If the firstName observable's value was changed to Ted, then the console would show first name: Ted.
This example creates an extender that forces writes to an observable to be numeric rounded to a configurable level of precision. In this case, the extender will return a new writeable computed observable that will sit in front of the real observable intercepting writes.
Note that for this to automatically erase rejected values from the UI, it's necessary to use .extend({ notify: 'always' }) on the computed observable. Without this, it's possible for the user to enter an invalid newValue that when rounded gives an unchanged valueToWrite. Then, since the model value would not be changing, there would be no notification to update the textbox in the UI. Using { notify: 'always' } causes the textbox to refresh (erasing rejected values) even if the computed property has not changed value.
This example creates an extender that allows an observable to be marked as required. Instead of returning a new object, this extender simply adds additional sub-observables to the existing observable. Since observables are functions, they can actually have their own properties. However, when the view model is converted to JSON, the sub-observables will be dropped and we will simply be left with the value of our actual observable. This is a nice way to add additional functionality that is only relevant for the UI and does not need to be sent back to the server.
More than one extender can be applied in a single call to the .extend method of an observable.
this.firstName = ko.observable(first).extend({ required: "Please enter a first name", logChange: "first name" });
In this case, both the required and logChange extenders would be executed against our observable.
Occasionally, you may find opportunities to streamline your code by attaching new functionality to Knockout's core value types. You can define custom functions on any of the following types:
TODO: HIERARCHY

Because of inheritance, if you attach a function to ko.subscribable, it will be available on all the others too. If you attach a function to ko.observable, it will be inherited by ko.observableArray but not by ko.computed.
To attach a custom function, add it to one of the following extensibility points:
ko.subscribable.fnko.observable.fnko.observableArray.fnko.computed.fnThen, your custom function will become available on all values of that type created from that point onwards.
Note: It's best to use this extensibility point only for custom functions that are truly applicable in a wide range of scenarios. You don't need to add a custom function to these namespaces if you're only planning to use it once.
Here's a way to define a filterByProperty function that will become available on all subsequently-created ko.observableArray instances:
ko.observableArray.fn.filterByProperty = function(propName, matchValue) {
return ko.computed(function() {
var allItems = this(), matchingItems = [];
for (var i = 0; i < allItems.length; i++) {
var current = allItems[i];
if (ko.unwrap(current[propName]) === matchValue)
matchingItems.push(current);
}
return matchingItems;
}, this);
}
This returns a new ko.computed value that provides a filtered view of the array, while leaving the original array unchanged. Because the filtered array is a ko.computed, it will be re-evaluated automatically whenever the underlying array changes.
The following live example shows how you could use this:
ko.observableArray.fn.filterByProperty = function(propName, matchValue) {
return ko.computed(function() {
var allItems = this(), matchingItems = [];
for (var i = 0; i < allItems.length; i++) {
var current = allItems[i];
if (ko.unwrap(current[propName]) === matchValue)
matchingItems.push(current);
}
return matchingItems;
}, this);
}
<h3>All tasks (<span data-bind="text: tasks().length"> </span>)</h3>
<ul data-bind="foreach: tasks">
<li>
<label>
<input type="checkbox" data-bind="checked: done" />
<span data-bind="text: title"> </span>
</label>
</li>
</ul>
<h3>Done tasks (<span data-bind="text: doneTasks().length"> </span>)</h3>
<ul data-bind="foreach: doneTasks">
<li data-bind="text: title"></li>
</ul>
function Task(title, done) {
this.title = ko.observable(title);
this.done = ko.observable(done);
}
function AppViewModel() {
this.tasks = ko.observableArray([
new Task('Find new desktop background', true),
new Task('Put shiny stickers on laptop', false),
new Task('Request more reggae music in the office', true)
]);
// Here's where we use the custom function
this.doneTasks = this.tasks.filterByProperty("done", true);
}
ko.applyBindings(new AppViewModel());
If you tend to filter observable arrays a lot, adding a filterByProperty globally to all observable arrays might make your code tidier. But if you only need to filter occasionally, you could instead choose not to attach to ko.observableArray.fn, and instead just construct doneTasks by hand as follows:
this.doneTasks = ko.computed(function() {
var all = this.tasks(), done = [];
for (var i = 0; i < all.length; i++)
if (all[i].done())
done.push(all[i]);
return done;
}, this);
The foreach binding duplicates a section of markup for each entry in an array, and binds each copy of that markup to the corresponding array item. This is especially useful for rendering lists or tables.
Assuming your array is an observable array, whenever you later add, remove, or re-order array entries, the binding will efficiently update the UI to match - inserting or removing more copies of the markup, or re-ordering existing DOM elements, without affecting any other DOM elements. This is far faster than regenerating the entire foreach output after each array change.
Of course, you can arbitrarily nest any number of foreach bindings along with other control-flow bindings such as if and with.
This example uses foreach to produce a read-only table with a row for each array entry.
Note: Table headers might disappear if the screen is small.
The following example shows that, if your array is observable, then the UI will be kept in sync with changes to that array.
Main parameter
Pass the array that you wish to iterate over. The binding will output a section of markup for each entry.
Alternatively, pass a JavaScript object literal with a property called data which is the array you wish to iterate over. The object
literal may also have other properties, such as afterAdd or includeDestroyed --- see below for details of these extra options and
examples of their use.
If the array you supply is observable, the foreach binding will respond to any future changes in the array's contents by adding or
removing corresponding sections of markup in the DOM.
Additional parameters
As shown in the above examples, bindings within the foreach block can refer to properties on the array entries. For example, Example 1 referenced the firstName and lastName properties on each array entry.
But what if you want to refer to the array entry itself (not just one of its properties)? In that case, you can use the special context property $data. Within a foreach block, it means "the current item". For example,
If you wanted, you could use $data as a prefix when referencing properties on each entry. For example, you could rewrite part of Example 1 as follows:
<td data-bind="text: $data.firstName"></td>
... but you don't have to, because firstName will be evaluated within the context of $data by default anyway.
As you can see from Example 2 above, it's possible to use $index to refer to the zero-based index of the current array item. $index is an observable and is updated whenever the index of the item changes (e.g., if items are added to or removed from the array).
Similarly, you can use $parent to refer to data from outside the foreach, e.g.:
<h1 data-bind="text: blogPostTitle"></h1>
<ul data-bind="foreach: likes">
<li>
<b data-bind="text: name"></b> likes the blog
post <b data-bind="text: $parent.blogPostTitle"></b>
</li>
</ul>
For more information about $index and other context properties such as $parent, see documentation for binding context properties.
As described in Note 1, you can refer to each array entry using the $data context variable. In some cases though, it may be useful to give the current item a more descriptive name using the as option like:
<ul data-bind="foreach: { data: people, as: 'person' }"></ul>
Now anywhere inside this foreach loop, bindings will be able to refer to person to access the current array item, from the people array, that is being rendered. This can be especially useful in scenarios where you have nested foreach blocks and you need to refer to an item declared at a higher level in the hierarchy. For example:
Tip: Remember to pass a string literal value to as (e.g., as: 'category', not as: category), because you are giving a name for a new variable, not reading the value of a variable that already exists.
In some cases, you might want to duplicate a section of markup, but you don't have any container element on which to put a foreach binding. For example, you might want to generate the following:
<ul>
<li class="header">Header item</li>
<!-- The following are generated dynamically from an array -->
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
In this example, there isn't anywhere to put a normal foreach binding. You can't put it on the <ul> (because then you'd be duplicating the header item), nor can you put a further container inside the <ul> (because only <li> elements are allowed inside <ul>s).
To handle this, you can use the containerless control flow syntax, which is based on comment tags. For example,
The <!-- ko --> and <!-- /ko --> comments act as start/end markers, defining a "virtual element" that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.
When you modify the contents of your model array (by adding, moving, or deleting its entries), the foreach binding uses an efficient differencing algorithm to figure out what has changed, so it can then update the DOM to match. This means it can handle arbitrary combinations of simulaneous changes.
foreach will render new copies of your template and insert them into the existing DOMforeach will simply remove the corresponding DOM elementsforeach will typically just move the corresponding DOM elements into their new positionNote that reordering detection is not guaranteed: to ensure the algorithm completes quickly, it is optimized to detect "simple" movements of small numbers of array entries. If the algorithm detects too many simultaneous reorderings combined with unrelated insertions and deletions, then for speed it can choose to regard a reordering as an "delete" plus an "add" instead of a single "move", and in that case the corresponding DOM elements will be torn down and recreated. Most developers won't encounter this edge case, and even if you do, the end-user experience will usually be identical.
Sometimes you may want to mark an array entry as deleted, but without actually losing record of its existence. This is known as a non-destructive delete. For details of how to do this, see the destroy function on observableArray.
By default, the foreach binding will skip over (i.e., hide) any array entries that are marked as destroyed. If you want to show destroyed entries, use the includeDestroyed option. For example,
<div data-bind='foreach: { data: myArray, includeDestroyed: true }'>
...
</div>
If you need to run some further custom logic on the generated DOM elements, you can use any of the afterRender/afterAdd/beforeRemove/beforeMove/afterMove callbacks described below.
Note: These callbacks are only intended for triggering animations related to changes in a list. If your goal is actually to attach other behaviors to new DOM elements when they have been added (e.g., event handlers, or to activate third-party UI controls), then your work will be much easier if you implement that new behavior as a custom binding instead, because then you can use that behavior anywhere, independently of the
foreachbinding.
Here's a trivial example that uses afterAdd to apply the classic "yellow fade" effect to newly-added items. It requires the jQuery Color plugin to enable animation of background colors.
Full details:
afterRender --- is invoked each time the foreach block is duplicated and inserted into the document, both when foreach first initializes, and when new entries are added to the associated array later. Knockout will supply the following parameters to your callback:
afterAdd --- is like afterRender, except it is invoked only when new entries are added to your array (and not when foreach first iterates over your array's initial contents). A common use for afterAdd is to call a method such as jQuery's $(domNode).fadeIn() so that you get animated transitions whenever items are added. Knockout will supply the following parameters to your callback:
beforeRemove --- is invoked when an array item has been removed, but before the corresponding DOM nodes have been removed. If you specify a beforeRemove callback, then it becomes your responsibility to remove the DOM nodes. The obvious use case here is calling something like jQuery's $(domNode).fadeOut() to animate the removal of the corresponding DOM nodes --- in this case, Knockout cannot know how soon it is allowed to physically remove the DOM nodes (who knows how long your animation will take?), so it is up to you to remove them. Knockout will supply the following parameters to your callback:
beforeMove --- is invoked when an array item has changed position in the array, but before the corresponding DOM nodes have been moved. Note that beforeMove applies to all array elements whose indexes have changed, so if you insert a new item at the beginning of an array, then the callback (if specified) will fire for all other elements, since their index position has increased by one. You could use beforeMove to store the original screen coordinates of the affected elements so that you can animate their movements in the afterMove callback. Knockout will supply the following parameters to your callback:
afterMove --- is invoked after an array item has changed position in the array, and after foreach has updated the DOM to match. Note that afterMove applies to all array elements whose indexes have changed, so if you insert a new item at the beginning of an array, then the callback (if specified) will fire for all other elements, since their index position has increased by one. Knockout will supply the following parameters to your callback:
For examples of afterAdd and beforeRemove see animated transitions.
The hasFocus binding links a DOM element's focus state with a viewmodel property. It is a two-way binding, so:
true or false, the associated element will become focused or unfocused.true or false accordingly.This is useful if you're building sophisticated forms in which editable elements appear dynamically, and you would like to control where the user should start typing, or respond to the location of the caret.
This example simply displays a message if the textbox currently has focus, and uses a button to show that you can trigger focus programmatically.
Because the hasFocus binding works in both directions (setting the associated value focuses or unfocuses the element; focusing or unfocusing the element sets the associated value), it's a convenient way to toggle an "edit" mode. In this example, the UI displays either a <span> or an <input> element depending on the model's editing property. Unfocusing the <input> element sets editing to false, so the UI switches out of "edit" mode.
Main parameter
Pass true (or some value that evaluates as true) to focus the associated element. Otherwise, the associated element will be unfocused.
When the user manually focuses or unfocuses the element, your value will be set to true or false accordingly.
If the value you supply is observable, the hasFocus binding will update the element's focus state whenever that observable value changes.
Additional parameters
The html binding causes the associated DOM element to display the HTML specified by your parameter.
Typically this is useful when values in your view model are actually strings of HTML markup that you want to render.
<div data-bind="html: details"></div>
var viewModel = {
details: ko.observable() // Initially blank
};
viewModel.details("<em>For further details, view the report <a href='report.html'>here</a>.</em>"); // HTML content appears
Main parameter
KO clears the previous content and then sets the element's content to your parameter value using jQuery's html function or by parsing the string into HTML nodes and appending each node as a child of the element, if jQuery is not available.
If this parameter is an observable value, the binding will update the element's content whenever the value changes. If the parameter isn't observable, it will only set the element's content once and will not update it again later.
If you supply something other than a number or a string (e.g., you pass an object or an array), the innerHTML will be equivalent to yourParameter.toString()
Additional parameters
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 (for example, if it is based on a different user's input that was stored in your database), then you can use the text binding, which will set the element's text value using innerText or textContent instead.
The if binding causes a section of markup to appear in your document (and to have its data-bind attributes applied), only if a specified expression evaluates to true (or a true-ish value such as a non-null object or nonempty string).
if plays a similar role to the visible binding. The difference is that, with visible, the contained markup always remains in the DOM and always has its data-bind attributes applied - the visible binding just uses CSS to toggle the container element's visiblity. The if binding, however, physically adds or removes the contained markup in your DOM, and only applies bindings to descendants if the expression is true.
This example shows that the if binding can dynamically add and remove sections of markup as observable values change.
In the following example, the <div> element will be empty for "Mercury", but populated for "Earth". That's because Earth has a non-null capital property, whereas "Mercury" has null for that property.
<ul data-bind="foreach: planets">
<li>
Planet: <b data-bind="text: name"> </b>
<div data-bind="if: capital">
Capital: <b data-bind="text: capital.cityName"> </b>
</div>
</li>
</ul>
ko.applyBindings({
planets: [
{ name: 'Mercury', capital: null },
{ name: 'Earth', capital: { cityName: 'Barnsley' } }
]
});
It's important to understand that the if binding really is vital to make this code work properly. Without it, there would be an error when trying to evaluate capital.cityName in the context of "Mercury" where capital is null. In JavaScript, you're not allowed to evaluate subproperties of null or undefined values.
Main parameter
The expression you wish to evaluate. If it evaluates to true (or a true-ish value), the contained markup will be present in the document, and any data-bind attributes on it will be applied. If your expression evaluates to false, the contained markup will be removed from your document without first applying any bindings to it.
If your expression involves any observable values, the expression will be re-evaluated whenever any of them change. Correspondingly, the markup within your if block can be added or removed dynamically as the result of the expression changes. data-bind attributes will be applied to a new copy of the contained markup whenever it is re-added.
Additional parameters
Sometimes you may want to control the presence/absence of a section of markup without having any container element that can hold an if binding. For example, you might want to control whether a certain <li> element appears alongside siblings that always appear:
<ul>
<li>This item always appears</li>
<li>I want to make this item present/absent dynamically</li>
</ul>
In this case, you can't put if on the <ul> (because then it would affect the first <li> too), and you can't put any other container around the second <li> (because HTML doesn't allow extra containers within <ul>s).
To handle this, you can use the containerless control flow syntax, which is based on comment tags. For example,
<ul>
<li>This item always appears</li>
<!-- ko if: someExpressionGoesHere -->
<li>I want to make this item present/absent dynamically</li>
<!-- /ko -->
</ul>
The <!-- ko --> and <!-- /ko --> comments act as start/end markers, defining a "virtual element" that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.
The ifnot binding is exactly the same as the if binding, except that it inverts the result of whatever expression you pass to it. For more details, see documentation for the if binding.
The following markup:
<div data-bind="ifnot: someProperty">...</div>
... is equivalent to the following:
<div data-bind="if: !someProperty()">...</div>
... assuming that someProperty is observable and hence you need to invoke it as a function to obtain the current value.
The only reason to use ifnot instead of a negated if is just as a matter of taste: many developers feel that it looks tidier.
Simply reference the JavaScript file using a <script> tag somewhere on your HTML pages. For example,
<script type='text/javascript' src='knockout-3.1.0.js'></script>
Change the src attribute to match the location where you put
the download file, or use one of the Content Delivery Networks at
the footer of this page.
You can also get Knockout over bower:
$ bower install knockoutjs
and npm:
$ npm install knockout
Next, if you are new to Knockout, you can get started with interactive tutorials, or explore the documentation.
Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. Any time you have sections of UI that update dynamically (e.g., changing depending on the user's actions or when an external data source changes), KO can help you implement it more simply and maintainably.
Headline features:
Additional benefits:
Developers familiar with Ruby on Rails, ASP.NET MVC, or other MV* technologies may see MVVM as a real-time form of MVC with declarative syntax. In another sense, you can think of KO as a general way to make UIs for editing JSON data... whatever works for you :)
The quickest and most fun way to get started is by working through the interactive tutorials. Once you've got to grips with the basics, explore the live examples and then have a go with it in your own project.
Everyone loves jQuery! It's an outstanding replacement for the clunky, inconsistent DOM API we had to put up with in the past. jQuery is an excellent low-level way to manipulate elements and event handlers in a web page. KO solves a different problem.
As soon as your UI gets nontrivial and has a few overlapping behaviors, things can get tricky and expensive to maintain if you only use jQuery. Consider an example: you're displaying a list of items, stating the number of items in that list, and want to enable an 'Add' button only when there are fewer than 5 items. jQuery doesn't have a concept of an underlying data model, so to get the number of items you have to infer it from the number of TRs in a table or the number of DIVs with a certain CSS class. Maybe the number of items is displayed in some SPAN, and you have to remember to update that SPAN's text when the user adds an item. You also must remember to disable the 'Add' button when the number of TRs is 5. Later, you're asked also to implement a 'Delete' button and you have to figure out which DOM elements to change whenever it's clicked.
It's much easier with KO. It lets you scale up in complexity without fear of introducing inconsistencies. Just represent your items as a JavaScript array, and then use a foreach binding to transform this array into a TABLE or set of DIVs. Whenever the array changes, the UI changes to match (you don't have to figure out how to inject new TRs or where to inject them). The rest of the UI stays in sync. For example, you can declaratively bind a SPAN to display the number of items as follows:
There are <span data-bind="text: myItems().count"></span> items
That's it! You don't have to write code to update it; it updates on its own when the myItems array changes. Similarly, to make the 'Add' button enable or disable depending on the number of items, just write:
<button data-bind="enable: myItems().count < 5">Add</button>
Later, when you're asked to implement the 'Delete' functionality, you don't have to figure out what bits of the UI it has to interact with; you just make it alter the underlying data model.
To summarise: KO doesn't compete with jQuery or similar low-level DOM APIs. KO provides a complementary, high-level way to link a data model to a UI. KO itself doesn't depend on jQuery, but you can certainly use jQuery at the same time, and indeed that's often useful if you want things like animated transitions.
Knockout allows you to implement sophisticated client-side interactivity, but almost all web applications also need to exchange data with the server, or at least to serialize the data for local storage. The most convenient way to exchange or store data is in JSON format - the format that the majority of Ajax applications use today.
Knockout doesn't force you to use any one particular technique to load or save data. You can use whatever mechanism is a convenient fit for your chosen server-side technology. The most commonly-used mechanism is jQuery's Ajax helper methods, such as getJSON, post, and ajax. You can fetch data from the server:
$.getJSON("/some/url", function(data) {
// Now use this data to update your view models,
// and Knockout will update your UI automatically
})
... or you can send data to the server:
var data = /* Your data in JSON format - see below */;
$.post("/some/url", data, function(returnedData) {
// This callback is executed if the post was successful
})
Or, if you don't want to use jQuery, you can use any other mechanism for loading or saving JSON data. So, all Knockout needs to help you do is:
Your view models are JavaScript objects, so in a sense, you could just serialize them as JSON using any standard JSON serializer, such as JSON.stringify (a native function in modern browsers), or the json2.js library. However, your view models probably contain observables, computed observables, and observable arrays, which are implemented as JavaScript functions and therefore won't always serialize cleanly without additional work on your behalf.
To make it easy to serialize view model data, including observables and the like, Knockout includes two helper functions:
ko.toJS --- this clones your view model's object graph, substituting for each observable the current value of that observable, so you get a plain copy that contains only your data and no Knockout-related artifactsko.toJSON --- this produces a JSON string representing your view model's data. Internally, it simply calls ko.toJS on your view model, and then uses the browser's native JSON serializer on the result. Note: for this to work on older browsers that have no native JSON serializer (e.g., IE 7 or earlier), you must also reference the json2.js library.For example, define a view model as follows:
var viewModel = {
firstName : ko.observable("Bert"),
lastName : ko.observable("Smith"),
pets : ko.observableArray(["Cat", "Dog", "Fish"]),
type : "Customer"
};
viewModel.hasALotOfPets = ko.computed(function() {
return this.pets().length > 2
}, viewModel)
This contains a mix of observables, computed observables, observable arrays, and plain values. You can convert it to a JSON string suitable for sending to the server using ko.toJSON as follows:
var jsonData = ko.toJSON(viewModel);
// Result: jsonData is now a string equal to the following value
// '{"firstName":"Bert","lastName":"Smith","pets":["Cat","Dog","Fish"],"type":"Customer","hasALotOfPets":true}'
Or, if you just want the plain JavaScript object graph before serialization, use ko.toJS as follows:
var plainJs = ko.toJS(viewModel);
// Result: plainJS is now a plain JavaScript object in which nothing is observable. It's just data.
// The object is equivalent to the following:
// {
// firstName: "Bert",
// lastName: "Smith",
// pets: ["Cat","Dog","Fish"],
// type: "Customer",
// hasALotOfPets: true
// }
Note that ko.toJSON accepts the same arguments as JSON.stringify. For example, it can be useful to have a "live" representation of your view model data when debugging a Knockout application. To generate a nicely formatted display for this purpose, you can pass the spaces argument into ko.toJSON and bind against your view model like:
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
If you've loaded some data from the server and want to use it to update your view model, the most straightforward way is to do it yourself. For example,
// Load and parse the JSON
var someJSON = /* Omitted: fetch it from the server however you want */;
var parsed = JSON.parse(someJSON);
// Update view model properties
viewModel.firstName(parsed.firstName);
viewModel.pets(parsed.pets);
In many scenarios, this direct approach is the simplest and most flexible solution. Of course, as you update the properties on your view model, Knockout will take care of updating the visible UI to match it.
However, many developers prefer to use a more conventions-based approach to updating their view models using incoming data without manually writing a line of code for every property to be updated. This can be beneficial if your view models have many properties, or deeply nested data structures, because it can greatly reduce the amount of manual mapping code you need to write. For more details about this technique, see the knockout.mapping plugin.
See these external pages for more examples of using Knockout with other technologies:
Still collecting links for this list - if you want to see your blog post here, tell us about it
If you want to detect and respond to changes on one object, you'd use observables. If you want to detect and respond to changes of a collection of things, use an observableArray. This is useful in many scenarios where you're displaying or editing multiple values and need repeated sections of UI to appear and disappear as items are added and removed.
var myObservableArray = ko.observableArray(); // Initially an empty array
myObservableArray.push('Some value'); // Adds the value and notifies observers
To see how you can bind the observableArray to a UI and let the user modify it, see the simple list example.
Simply putting an object into an observableArray doesn't make all of that object's properties themselves observable. Of course, you can make those properties observable if you wish, but that's an independent choice. An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.
If you want your observable array not to start empty, but to contain some initial items, pass those items as an array to the constructor. For example,
// This observable array initially contains three objects
var anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
Behind the scenes, an observableArray is actually an observable whose value is an array (plus, observableArray adds some additional features described below). So, you can get the underlying JavaScript array by invoking the observableArray as a function with no parameters, just like any other observable. Then you can read information from that underlying array. For example,
alert('The length of the array is ' + myObservableArray().length);
alert('The first element is ' + myObservableArray()[0]);
Technically you can use any of the native JavaScript array functions to operate on that underlying array, but normally there's a better alternative. KO's observableArray has equivalent functions of its own, and they're more useful because:
indexOf function doesn't work on IE 8 or earlier, but KO's indexOf works everywhere.)push and splice, KO's methods automatically trigger the dependency tracking mechanism so that all registered listeners are notified of the change, and your UI is automatically updated.push method, just write myObservableArray.push(...). This is slightly nicer than calling the underlying array's push method by writing myObservableArray().push(...).The rest of this page describes observableArray's functions for reading and writing array information.
The indexOf function returns the index of the first array item that equals your parameter. For example, myObservableArray.indexOf('Blah') will return the zero-based index of the first array entry that equals Blah, or the value -1 if no matching value was found.
The slice function is the observableArray equivalent of the native JavaScript slice function (i.e., it returns the entries of your array from a given start index up to a given end index). Calling myObservableArray.slice(...) is equivalent to calling the same method on the underlying array (i.e., myObservableArray().slice(...)).
observableArray exposes a familiar set of functions for modifying the contents of the array and notifying listeners.
All of these functions are equivalent to running the native JavaScript array functions on the underlying array, and then notifying listeners about the change:
myObservableArray.push('Some new value') adds a new item to the end of arraymyObservableArray.pop() removes the last value from the array and returns itmyObservableArray.unshift('Some new value') inserts a new item at the beginning of the arraymyObservableArray.shift() removes the first value from the array and returns itmyObservableArray.reverse() reverses the order of the arraymyObservableArray.sort() sorts the array contents.myObservableArray.sort(function(left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) })myObservableArray.splice() removes and returns a given number of elements starting from a given index. For example, myObservableArray.splice(1, 3) removes three elements starting from index position 1 (i.e., the 2nd, 3rd, and 4th elements) and returns them as an array.For more details about these observableArray functions, see the equivalent documentation of the standard JavaScript array functions.
observableArray adds some more useful methods that aren't found on JavaScript arrays by default:
myObservableArray.remove(someItem) removes all values that equal someItem and returns them as an arraymyObservableArray.remove(function(item) { return item.age < 18 }) removes all values whose age property is less than 18, and returns them as an arraymyObservableArray.removeAll(['Chad', 132, undefined]) removes all values that equal 'Chad', 123, or undefined and returns them as an arraymyObservableArray.removeAll() removes all values and returns them as an arrayThe destroy and destroyAll functions are mainly intended as a convenience for developers using Ruby on Rails:
myObservableArray.destroy(someItem) finds any objects in the array that equal someItem and gives them a special property called _destroy with value truemyObservableArray.destroy(function(someItem) { return someItem.age < 18 }) finds any objects in the array whose age property is less than 18, and gives those objects a special property called _destroy with value truemyObservableArray.destroyAll(['Chad', 132, undefined]) finds any objects in the array that equal 'Chad', 123, or undefined and gives them a special property called _destroy with value truemyObservableArray.destroyAll() gives a special property called _destroy with value true to all objects in the arraySo, what's this _destroy thing all about? It's only really interesting to Rails developers. The convention in Rails is that, when you pass into an action a JSON object graph, the framework can automatically convert it to an ActiveRecord object graph and then save it to your database. It knows which of the objects are already in your database, and issues the correct INSERT or UPDATE statements. To tell the framework to DELETE a record, you just mark it with _destroy set to true.
Note that when KO renders a foreach binding, it automatically hides any objects marked with _destroy equal to true. So, you can have some kind of "delete" button that invokes the destroy(someItem) method on the array, and this will immediately cause the specified item to vanish from the visible UI. Later, when you submit the JSON object graph to Rails, that item will also be deleted from the database (while the other array items will be inserted or updated as usual).
Normally, an observableArray notifies its subscribers immediately, as soon as it's changed. But if an observableArray is changed repeatedly or triggers expensive updates, you may get better performance by limiting or delaying change notifications. This is accomplished using the rateLimit extender like this:
// Ensure it notifies about changes no more than once per 50-millisecond period
myViewModel.myObservableArray.extend({ rateLimit: 50 });
Knockout is built around three core features:
On this page, you'll learn about the first of these three. But before that, let's examine the MVVM pattern and the concept of a view model.
Model-View-View Model (MVVM) is a design pattern for building user interfaces. It describes how you can keep a potentially sophisticated UI simple by splitting it into three parts:
A model: your application's stored data. This data represents objects and operations in your business domain (e.g., bank accounts that can perform money transfers) and is independent of any UI. When using KO, you will usually make Ajax calls to some server-side code to read and write this stored model data.
A view model: a pure-code representation of the data and operations on a UI. For example, if you're implementing a list editor, your view model would be an object holding a list of items, and exposing methods to add and remove items.
Note that this is not the UI itself: it doesn't have any concept of buttons or display styles. It's not the persisted data model either - it holds the unsaved data the user is working with. When using KO, your view models are pure JavaScript objects that hold no knowledge of HTML. Keeping the view model abstract in this way lets it stay simple, so you can manage more sophisticated behaviors without getting lost.
A view: a visible, interactive UI representing the state of the view model. It displays information from the view model, sends commands to the view model (e.g., when the user clicks buttons), and updates whenever the state of the view model changes.
When using KO, your view is simply your HTML document with declarative bindings to link it to the view model. Alternatively, you can use templates that generate HTML using data from your view model.
To create a view model with KO, just declare any JavaScript object. For example,
var myViewModel = {
personName: 'Bob',
personAge: 123
};
You can then create a very simple view of this view model using a declarative binding. For example, the following markup displays the personName value:
The name is <span data-bind="text: personName"></span>
The data-bind attribute isn't native to HTML, though it is perfectly OK (it's strictly compliant in HTML 5, and causes no problems with HTML 4 even though a validator will point out that it's an unrecognized attribute). But since the browser doesn't know what it means, you need to activate Knockout to make it take effect.
To activate Knockout, add the following line to a <script> block:
ko.applyBindings(myViewModel);
You can either put the script block at the bottom of your HTML document, or you can put it at the top and wrap the contents in a DOM-ready handler such as jQuery's $ function.
That does it! Now, your view will display as if you'd written the following HTML:
The name is <span>Bob</span>
In case you're wondering what the parameters to ko.applyBindings do,
The first parameter says what view model object you want to use with the declarative bindings it activates
Optionally, you can pass a second parameter to define which part of the document you want to search for data-bind attributes. For example, ko.applyBindings(myViewModel, document.getElementById('someElementId')). This restricts the activation to the element with ID someElementId and its descendants, which is useful if you want to have multiple view models and associate each with a different region of the page.
Pretty simple, really.
OK, you've seen how to create a basic view model and how to display one of its properties using a binding. But one of the key benefits of KO is that it updates your UI automatically when the view model changes. How can KO know when parts of your view model change? Answer: you need to declare your model properties as observables, because these are special JavaScript objects that can notify subscribers about changes, and can automatically detect dependencies.
For example, rewrite the preceding view model object as follows:
var myViewModel = {
personName: ko.observable('Bob'),
personAge: ko.observable(123)
};
You don't have to change the view at all - the same data-bind syntax will keep working. The difference is that it's now capable of detecting changes, and when it does, it will update the view automatically.
Not all browsers support JavaScript getters and setters (* cough * IE * cough *), so for compatibility, ko.observable objects are actually functions.
To read the observable's current value, just call the observable with no parameters. In this example, myViewModel.personName() will return 'Bob', and myViewModel.personAge() will return 123.
To write a new value to the observable, call the observable and pass the new value as a parameter. For example, calling myViewModel.personName('Mary') will change the name value to 'Mary'.
To write values to multiple observable properties on a model object, you can use chaining syntax. For example, myViewModel.personName('Mary').personAge(50) will change the name value to 'Mary' and the age value to 50.
The whole point of observables is that they can be observed, i.e., other code can say that it wants to be notified of changes. That's what many of KO's built-in bindings do internally. So, when you wrote data-bind="text: personName", the text binding registered itself to be notified when personName changes (assuming it's an observable value, which it is now).
When you change the name value to 'Mary' by calling myViewModel.personName('Mary'), the text binding will automatically update the text contents of the associated DOM element. That's how changes to the view model automatically propagate to the view.
You won't normally need to set up subscriptions manually, so beginners should skip this section.
For advanced users, if you want to register your own subscriptions to be notified of changes to observables, you can call their subscribe function. For example:
myViewModel.personName.subscribe(function(newValue) {
alert("The person's new name is " + newValue);
});
The subscribe function is how many parts of KO work internally. Most of the time you don't need to use this, because the built-in bindings and templating system take care of managing subscriptions.
The subscribe function accepts three parameters: callback is the function that is called whenever the notification happens, target (optional) defines the value of this in the callback function, and event (optional; default is "change") is the name of the event to receive notification for.
You can also terminate a subscription if you wish: first capture the return value as a variable, then you can call its dispose function, e.g.:
var subscription = myViewModel.personName.subscribe(function(newValue) { /* do stuff */ });
// ...then later...
subscription.dispose(); // I no longer want notifications
If you want to be notified of the value of an observable before it is about to be changed, you can subscribe to the beforeChange event. For example:
myViewModel.personName.subscribe(function(oldValue) {
alert("The person's previous name is " + oldValue);
}, null, "beforeChange");
Note: Knockout does not guarantee that the beforeChange and change events will occur in pairs, since other parts of your code might raise either event individually. If you need to track the previous value of an observable, it's up to you to use a subscription to capture and track it.
When writing to an observable that contains a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in notify extender to ensure that an observable's subscribers are always notified on a write, even if the value is the same. You would apply the extender to an observable like this:
myViewModel.personName.extend({ notify: 'always' });
Normally, an observable notifies its subscribers immediately, as soon as it's changed. But if an observable is changed repeatedly or triggers expensive updates, you may get better performance by limiting or delaying the observable's change notifications. This is accomplished using the rateLimit extender like this:
// Ensure it notifies about changes no more than once per 50-millisecond period
myViewModel.personName.extend({ rateLimit: 50 });
The options binding controls what options should appear in a drop-down list (i.e., a <select> element) or multi-select list (e.g., <select size='6'>). This binding cannot be used with anything other than <select> elements.
The value you assign should be an array (or observable array). The <select> element will then display one item for each item in your array.
Note: 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.
<p>
Destination country:
<select data-bind="options: availableCountries"></select>
</p>
var viewModel = {
// These are the initial options
availableCountries: ko.observableArray(['France', 'Germany', 'Spain'])
};
// ... then later ...
viewModel.availableCountries.push('China'); // Adds another option
<p>
Choose some countries you would like to visit:
<select data-bind="options: availableCountries" size="5" multiple="true"></select>
</p>
var viewModel = {
availableCountries: ko.observableArray(['France', 'Germany', 'Spain'])
};
<p>
Your country:
<select data-bind="options: availableCountries,
optionsText: 'countryName',
value: selectedCountry,
optionsCaption: 'Choose...'"></select>
</p>
<div data-bind="visible: selectedCountry"> <!-- Appears when you select something -->
You have chosen a country with population
<span data-bind="text: selectedCountry() ? selectedCountry().countryPopulation : 'unknown'"></span>.
</div>
// Constructor for an object with two properties
var Country = function(name, population) {
this.countryName = name;
this.countryPopulation = population;
};
var viewModel = {
availableCountries : ko.observableArray([
new Country("UK", 65000000),
new Country("USA", 320000000),
new Country("Sweden", 29000000)
]),
selectedCountry : ko.observable() // Nothing selected by default
};
<!-- Same as example 3, except the <select> box expressed as follows: -->
<select data-bind="options: availableCountries,
optionsText: function(item) {
return item.countryName + ' (pop: ' + item.countryPopulation + ')'
},
value: selectedCountry,
optionsCaption: 'Choose...'"></select>
Note that the only difference between examples 3 and 4 is the optionsText value.
Main parameter
You should supply an array (or observable array). For each item, KO will add an <option> to the associated <select> node. Any previous options will be removed.
If your parameter's value is an array of strings, you don't need to give any other parameters. The <select> element will display an option for each string value. However, if you want to let the user choose from an array of arbitrary JavaScript objects (not merely strings), then see the optionsText and optionsValue parameters below.
If this parameter is an observable value, the binding will update the element's available options whenever the value changes. If the parameter isn't observable, it will only set the element's available options once and will not update them again later.
Additional parameters
optionsCaption
Sometimes, you might not want to select any particular option by default. But a single-select drop-down list usually starts with some item selected, so how can you avoid preselecting something? The usual solution is to prefix the list of options with a special dummy option that just reads "Select an item" or "Please choose an option" or similar, and have that one selected by default.
This easy to do: just add an additional parameter with name optionsCaption, with its value being a string to display. For example:
<select data-bind='options: myOptions, optionsCaption: "Select an item...", value: myChosenValue'></select>
KO will prefix the list of items with one that displays the text "Select an item..." and has the value undefined. So, if myChosenValue holds the value undefined (which observables do by default), then the dummy option will be selected. If the optionsCaption parameter is an observable, then the text of the initial item will update as the observable's value changes.
optionsText
See Example 3 above to see how you can bind options to an array of arbitrary JavaScript object - not just strings. In this case, you need to choose which of the objects' properties should be displayed as the text in the drop-down list or multi-select list. Example 3 shows how you can specify that property name by passing an additional parameter called optionsText.
If you don't want to display just a simple property value as the text for each item in the dropdown, you can pass a JavaScript function for the optionsText option and supply your own arbitrary logic for computing the displayed text in terms of the represented object. See Example 4 above, which shows how you could generate the displayed text by concatenating together multiple property values.
optionsValue
Similar to optionsText, you can also pass an additional parameter called optionsValue to specify which of the objects' properties should be used to set the value attribute on the <option> elements that KO generates. You can also specify a JavaScript function to determine this value. This function will receive the selected item as its only argument and should return a string to use for the <option> element's value attribute.
Typically you'd only want to use optionsValue as a way of ensuring that KO can correctly retain selection when you update the set of available options. For example, if you're repeatedly getting a list of "car" objects via Ajax calls and want to ensure that the selected car is preserved, you might need to set optionsValue to "carId" or whatever unique identifier each "car" object has, otherwise KO won't necessarily know which of the previous "car" objects corresponds to which of the new ones.
optionsIncludeDestroyed
Sometimes you may want to mark an array entry as deleted, but without actually losing record of its existence. This is known as a non-destructive delete. For details of how to do this, see the destroy function on observableArray.
By default, the options binding will skip over (i.e., hide) any array entries that are marked as destroyed. If you want to show destroyed entries, then specify this additional parameter like:
<select data-bind='options: myOptions, optionsIncludeDestroyed: true'></select>
optionsAfterRender
If you need to run some further custom logic on the generated option elements, you can use the optionsAfterRender callback. See Note 2 below.
selectedOptions
For a multi-select list, you can read and write the selection state using selectedOptions. Technically this is a separate binding, so it has its own documentation.
valueAllowUnset
If you want Knockout to allow your model property to take values that have no corresponding entry in your <select> element (and display this by making the <select> element blank), then see documentation for valueAllowUnset.
When the options binding changes the set of options in your <select> element, KO will leave the user's selection unchanged where possible. So, for a single-select drop-down list, the previously selected option value will still be selected, and for a multi-select list, all the previously selected option values will still be selected (unless, of course, you've removed one or more of those options).
That's because the options binding tries to be independent of the value binding (which controls selection for a single-select list) and the selectedOptions binding (which controls selection for a multi-select list).
If you need to run some further custom logic on the generated option elements, you can use the optionsAfterRender callback. The callback function is invoked each time an option element is inserted into the list, with the following parameters:
option elementundefined for the caption elementHere's an example that uses optionsAfterRender to add a disable binding to each option.
<select size=3 data-bind="
options: myItems,
optionsText: 'name',
optionsValue: 'id',
optionsAfterRender: setOptionDisable">
</select>
var vm = {
myItems: [
{ name: 'Item 1', id: 1, disable: ko.observable(false)},
{ name: 'Item 3', id: 3, disable: ko.observable(true)},
{ name: 'Item 4', id: 4, disable: ko.observable(false)}
],
setOptionDisable: function(option, item) {
ko.applyBindingsToNode(option, {disable: item.disable}, item);
}
};
ko.applyBindings(vm);
None, other than the core Knockout library.
| Repository | About |
|---|---|
| {{ name }} | {{# template: "plugins-td" /}} |
Note: This rate-limit API was added in Knockout 3.1.0. For previous versions, the throttle extender provides similar functionality.
Normally, an observable that is changed notifies its subscribers immediately, so that any computed observables or bindings that depend on the observable are updated synchronously. The rateLimit extender, however, causes an observable to suppress and delay change notifications for a specified period of time. A rate-limited observable therefore updates dependencies asynchronously.
The rateLimit extender can be applied to any type of observable, including observable arrays and computed observables. The main use cases for rate-limiting are:
rateLimit supports two parameter formats:
// Shorthand: Specify just a timeout in milliseconds
someObservableOrComputed.extend({ rateLimit: 500 });
// Longhand: Specify timeout and/or method
someObservableOrComputed.extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } });
The method option controls when notifications fire, and accepts the following values:
notifyAtFixedRate --- Default value if not otherwise specified. The notification happens after the specified period of time from the first change to the observable (either initially or since the previous notification).
notifyWhenChangesStop --- The notification happens after no changes have occured to the observable for the specified period of time. Each time the observable changes, that timer is reset, so notifications cannot happen if the observable continuously changes more frequently than the timeout period.
Consider the observables in the following code:
var name = ko.observable('Bert');
var upperCaseName = ko.computed(function() {
return name().toUpperCase();
});
Normally, if you change name as follows:
name('The New Bert');
... then upperCaseName will be recomputed immediately, before your next line of code runs. But if you instead define name using rateLimit as follows:
var name = ko.observable('Bert').extend({ rateLimit: 500 });
... then upperCaseName will not be recomputed immediately when name changes---instead, name will wait for 500 milliseconds (half a second) before notifying its new value to upperCaseName, which will then recompute its value. No matter how many times name is changed during those 500 ms, upperCaseName will only be updated once with the most recent value.
In this live example, there's an instantaneousValue observable that reacts immediately when you press a key. This is then wrapped inside a delayedValue computed observable that's configured to notify only when changes stop for at least 400 milliseconds, using the notifyWhenChangesStop rate-limit method.
Try it:
The following model represents data that you could render as a paged grid:
function GridViewModel() {
this.pageSize = ko.observable(20);
this.pageIndex = ko.observable(1);
this.currentPageData = ko.observableArray();
// Query /Some/Json/Service whenever pageIndex or pageSize changes,
// and use the results to update currentPageData
ko.computed(function() {
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this);
}
Because the computed observable evaluates both pageIndex and pageSize, it becomes dependent on both of them. So, this code will use jQuery's $.getJSON function to reload currentPageData when a GridViewModel is first instantiated and whenever the pageIndex or pageSize properties are later changed.
This is very simple and elegant (and it's trivial to add yet more observable query parameters that also trigger a refresh automatically whenever they change), but there is a potential efficiency problem. Suppose you add the following function to GridViewModel that changes both pageIndex and pageSize:
this.setPageSize = function(newPageSize) {
// Whenever you change the page size, we always reset the page index to 1
this.pageSize(newPageSize);
this.pageIndex(1);
}
The problem is that this will cause two Ajax requests: the first one will start when you update pageSize, and the second one will start immediately afterwards when you update pageIndex. This is a waste of bandwidth and server resources, and a source of unpredictable race conditions.
When applied to a computed observable, the rateLimit extender will also avoid excess evaluation of the computed function. Using a short rate-limit timeout (e.g., 0 milliseconds) ensures that any sequence of synchronous changes to dependencies will trigger just one re-evaluation of your computed observable. For example:
ko.computed(function() {
// This evaluation logic is exactly the same as before
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this).extend({ rateLimit: 0 });
Now you can change pageIndex and pageSize as many times as you like, and the Ajax call will only happen once after you release your thread back to the JavaScript runtime.
For a computed observable, the rate-limit timer is triggered when one of the computed observable's dependencies change instead of when its value changes. The computed observable is not re-evaluated until its value is actually needed---after the timeout period when the change notification should happen, or when the computed observable value is accessed directly. If you need to access the value of the computed's most recent evaluation, you can do so with the peek method.
When the value of any observable is primitive (a number, string, boolean, or null), the dependents of the observable are by default notified only when it is set to a value that is actually different from before. So, primitive-valued rate-limited observables notify only when their value is actually different at the end of the timeout period. In other words, if a primitive-valued rate-limited observable is changed to a new value and then changed back to the original value before the timeout period ends, no notification will happen.
If you want to ensure that the subscribers are always notified of an update, even if the value is the same, you would use the notify extender in addition to rateLimit:
myViewModel.fullName = ko.computed(function() {
return myViewModel.firstName() + " " + myViewModel.lastName();
}).extend({ notify: 'always', rateLimit: 500 });
If you'd like to migrate code from using the deprecated throttle extender, you should note the following ways that the rateLimit extender is different from the throttle extender.
When using rateLimit:
change notifications are delayed, including when calling valueHasMutated manually. This means you can't use valueHasMutated to force a rate-limited observable to notify an un-changed value.throttle algorithm. To match the throttle behavior, use the notifyWhenChangesStop method.The selectedOptions binding controls which elements in a multi-select list are currently selected. This is intended to be used in conjunction with a <select> element and the options binding.
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.
Likewise, assuming it's an observable array on your view model, then whenever you add or remove (e.g., via push or splice) items to this array, the corresponding items in the UI become selected or deselected. It's a 2-way binding.
Note: To control which element in a single-select drop-down list is selected, you can use the value binding instead.
<p>
Choose some countries you'd like to visit:
<select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select>
</p>
var viewModel = {
availableCountries : ko.observableArray(['France', 'Germany', 'Spain']),
chosenCountries : ko.observableArray(['Germany']) // Initially, only Germany is selected
};
// ... then later ...
viewModel.chosenCountries.push('France'); // Now France is selected too
Main parameter
This should be an array (or an observable array). KO sets the element's selected options to match the contents of the array. Any previous selection state will be overwritten.
If your parameter is an observable array, the binding will update the element's selection whenever the array changes (e.g., via push, pop or other observable array methods). If the parameter isn't observable, it will only set the element's selection state once and will not update it again later.
Whether or not the parameter is an observable array, KO will detect when the user selects or deselects an item in the multi-select list, and will update the array to match. This is how you can read which of the options is selected.
Additional parameters
None
In the example code above, the user can choose from an array of string values. You're not limited to providing strings - your options array can contain arbitrary JavaScript objects if you wish. See the options binding for details on how to control how arbitrary objects should be displayed in the list.
In this scenario, the values you can read and write using selectedOptions are those objects themselves, not their textual representations. This leads to much cleaner and more elegant code in most cases. Your view model can imagine that the user chooses from an array of arbitrary objects, without having to care how those objects are mapped to an on-screen representation.
The style binding adds or removes one or more style values to the associated DOM element. This is useful, for example, to highlight some value in red if it becomes negative, or to set the width of a bar to match a numerical value that changes.
(Note: If you don't want to apply an explicit style value but instead want to assign a CSS class, see the css binding.)
This will set the element's style.color property to red whenever the currentProfit value dips below zero, and to black whenever it goes above zero.
Main parameter
You should pass a JavaScript object in which the property names correspond to style names, and the values correspond to the style values you wish to apply.
You can set multiple style values at once. For example, if your view model has a property called isSevere,
<div data-bind="style: { color: currentProfit() < 0 ? 'red' : 'black', fontWeight: isSevere() ? 'bold' : '' }">...</div>
If your parameter references an observable value, the binding will update the styles whenever the observable value changes. If the parameter doesn't reference an observable value, it will only set the styles once and will not update them later.
As usual, you can use arbitrary JavaScript expressions or functions as parameter values. KO will evaluate them and use the resulting values to detemine the style values to apply.
Additional parameters
If you want to apply a font-weight or text-decoration style, or any other style whose name isn't a legal JavaScript identifier (e.g., because it contains a hyphen), you must use the JavaScript name for that style. For example,
{ font-weight: someValue }; do write { fontWeight: someValue }{ text-decoration: someValue }; do write { textDecoration: someValue }See also: a longer list of style names and their JavaScript equivalents
The submit binding adds an event handler so that your chosen JavaScript function will be invoked when the associated DOM element is submitted. Typically you will only want to use this on form elements.
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.
As illustrated in this example, KO passes the form element as a parameter to your submit handler function. You can ignore that parameter if you want, or there are various ways you might want to use it, for example:
Extracting additional data or state from the form elements
Triggering UI-level validation using a library such as jQuery Validation, using code similar to the following snippet: if ($(formElement).valid()) { /* do something */ }.
click handler on the submit button?Instead of using submit on the form, you could use click on the submit button. However, submit has the advantage that it also captures alternative ways to submit the form, such as pressing the enter key while typing into a text box.
Main parameter
The function you want to bind to the element's submit event.
You can reference any JavaScript function - it doesn't have to be a function on your view model. You can reference a function on any object by writing submit: someObject.someFunction.
Functions on your view model are slightly special because you can reference them by name, i.e., you can write submit: doSomething and don't have to write submit: viewModel.doSomething (though technically that's also valid).
Additional parameters
For information about how to pass additional parameters to your submit handler function, or how to control the this handle when invoking functions that aren't on your view model, see the notes relating to the click binding. All the notes on that page apply to submit handlers too.
The template binding populates the associated DOM element with the results of rendering a template. Templates are a simple and convenient way to build sophisticated UI structures - possibly with repeating or nested blocks - as a function of your view model data.
There are two main ways of using templates:
foreach, if, with, and other control flow bindings. Internally, those control
flow bindings capture the HTML markup contained in your element, and use it as a template to render against an arbitrary data item.
This feature is built into Knockout and doesn't require any external library.Main parameter
Shorthand syntax: If you just supply a string value, KO will interpret this as the ID of a template to render. The data it supplies to the template will be your current model object.
For more control, pass a JavaScript object with some combination of the following properties:
name --- the ID of an element that contains the template you wish to render - see Note 5 for how to vary this programmatically.data --- an object to supply as the data for the template to render. If you omit this parameter, KO will look for a foreach parameter, or will fall back on using your current model object.if --- if this parameter is provided, the template will only be rendered if the specified expression evaluates to true (or a true-ish value). This can be useful for preventing a null observable from being bound against a template before it is populated.foreach --- instructs KO to render the template in "foreach" mode - see Note 2 for details.as --- when used in conjunction with foreach, defines an alias for each item being rendered - see Note 3 for details.afterRender, afterAdd, or beforeRemove --- callback functions to be invoked against the rendered DOM elements - see Note 4Normally, when you're using control flow bindings (foreach, with, if, etc.), there's no need to give names to your templates: they are defined implicitly
and anonymously by the markup inside your DOM element. But if you want to, you can factor out templates into a separate element and then reference them by name:
In this example, the person-template markup is used twice: once for buyer, and once for seller. Notice that the template markup is wrapped in a script type="text/html" ---
the dummy type attribute is necessary to ensure that the markup is not executed as JavaScript, and Knockout does not attempt to apply
bindings to that markup except when it is being used as a template.
It's not very often that you'll need to use named templates, but on occasion it can help to minimise duplication of markup.
If you want the equivalent of a foreach binding, but using a named template, you can do so in the natural way:
This gives the same result as embedding an anonymous template directly inside the element to which you use foreach, i.e.:
<div data-bind="foreach: people">
<h3 data-bind="text: name"></h3>
<p>Credits: <span data-bind="text: credits"></span></p>
</div>
When nesting foreach templates, it's often useful to refer to items at higher levels in the hierarchy. One way to do this is to refer to $parent or other binding context variables in your bindings.
A simpler and more elegant option, however, is to use as to declare a name for your iteration variables. For example:
<ul data-bind="template: { name: 'employeeTemplate',
foreach: employees,
as: 'employee' }"></ul>
Notice the string value 'employee' associated with as. Now anywhere inside this foreach loop, bindings in your child templates will be able to refer to employee to access the employee object being rendered.
This is mainly useful if you have multiple levels of nested foreach blocks, because it gives you an unambiguous way to refer to any named item declared at a higher level in the hierarchy. Here's a complete example, showing how season can be referenced while rendering a month:
Tip: Remember to pass a string literal value to as (e.g., as: 'season', not as: season), because you are giving a name for a new variable, not reading the value of a variable that already exists.
Sometimes you might want to run custom post-processing logic on the DOM elements generated by your templates. For example, if you're using a JavaScript widgets library such as jQuery UI, you might want to intercept your templates' output so that you can run jQuery UI commands on it to transform some of the rendered elements into date pickers, sliders, or anything else.
Generally, the best way to perform such post-processing on DOM elements is to write a custom binding, but if you really just want to access the raw DOM elements emitted by a template, you can use afterRender.
Pass a function reference (either a function literal, or give the name of a function on your view model), and Knockout will invoke it immediately after rendering or re-rendering your template. If you're using foreach, Knockout will invoke your afterRender callback for each item added to your observable array. For example,
<div data-bind='template: { name: "personTemplate",
data: myData,
afterRender: myPostProcessingLogic }'> </div>
... and define a corresponding function on your view model (i.e., the object that contains myData):
viewModel.myPostProcessingLogic = function(elements) {
// "elements" is an array of DOM nodes just rendered by the template
// You can add custom post-processing logic here
}
If you are using foreach and only want to be notified about elements that are specifically being added or are being removed, you can use afterAdd and beforeRemove instead. For details, see documentation for the foreach binding.
If you have multiple named templates, you can pass an observable for the name option. As the observable's value is updated, the element's contents will be re-rendered using the appropriate template. Alternatively, you can pass a callback function to determine which template to use. If you are using the foreach template mode, Knockout will evaluate the function for each item in your array, passing that item's value as the only argument. Otherwise, the function will be given the data option's value or fall back to providing your whole current model object.
For example,
If your function references observable values, then the binding will update whenever any of those values change. This will cause the data to be re-rendered using the appropriate template.
If your function accepts a second parameter, then it will receive the entire binding context. You can then access $parent or any other binding context variable when dynamically choosing a template. For example, you could amend the preceding code snippet as follows:
displayMode: function(employee, bindingContext) {
// Now return a template name string based on properties of employee or bindingContext
}
In the vast majority of cases, Knockout's native templating and the foreach, if, with and other control flow bindings will be all you need to construct an arbitrarily sophisticated UI. But in case you wish to integrate with an external templating library, such as the Underscore template engine or jquery.tmpl, Knockout offers a way to do it.
By default, Knockout comes with support for jquery.tmpl. To use it, you need to reference the following libraries, in this order:
<!-- First jQuery --> script src="http://code.jquery.com/jquery-1.7.1.min.js"
<!-- Then jQuery.tmpl --> script src="jquery.tmpl.js"
<!-- Then Knockout --> script src="knockout-x.y.z.js"
Then, you can use jQuery.tmpl syntax in your templates. For example,
This works because {{'{{'}}each ...}} and ${ ... } are jQuery.tmpl syntaxes. What's more, it's trivial to nest templates: because you can use data-bind attributes from inside a template, you can simply put a data-bind="template: ..." inside a template to render a nested one.
Please note that, as of December 2011, jQuery.tmpl is no longer under active development. We recommend the use of Knockout's native DOM-based templating (i.e., the foreach, if, with, etc. bindings) instead of jQuery.tmpl or any other string-based template engine.
The Underscore.js template engine by default uses ERB-style delimiters (<%= ... %>). Here's how the preceding example's template might look with Underscore:
<script id='peopleList'>
<% _.each(people(), function(person) { %>
<li>
<b><%= person.name %></b> is <%= person.age %> years old
</li>
<% }) %>
</script>
Here's a simple implementation of integrating Underscore templates with Knockout. The integration code is just 16 lines long, but it's enough to support Knockout data-bind attributes (and hence nested templates) and Knockout binding context variables ($parent, $root, etc.).
If you're not a fan of the <%= ... %> delimiters, you can configure the Underscore template engine to use any other delimiter characters of your choice.
The text binding causes the associated DOM element to display the text value of your parameter.
Typically this is useful with elements like <span> or <em> that traditionally display text, but technically you can use it with any element.
Main parameter
Knockout sets the element's content to a text node with your parameter value. Any previous content will be overwritten.
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.
If you supply something other than a number or a string (e.g., you pass an object or an array), the displayed text will be equivalent to yourParameter.toString()
Additional parameters
If you want to detemine text programmatically, one option is to create a computed observable, and use its evaluator function as a place for your code that works out what text to display.
For example,
Now, the text will switch between "expensive" and "affordable" as needed whenever price changes.
Alternatively, you don't need to create a computed observable if you're doing something simple like this. You can pass an arbitrary JavaScript expression to the text binding. For example,
The item is
<span data-bind="text: price() > 50 ? 'expensive' : 'affordable'"></span>
today.
This has exactly the same result, without requiring the priceRating computed observable.
Since this binding sets your text value using a text node, it's safe to set any string value without risking HTML or script injection. For example, if you wrote:
viewModel.myMessage("<i>Hello, world!</i>");
... this would not render as italic text, but would render as literal text with visible angle brackets.
If you need to set HTML content in this manner, see the html binding.
Sometimes you may want to set text using Knockout without including an extra element for the text binding. For example, you're not allowed to include other elements within an option element, so the following will not work.
<select data-bind="foreach: items">
<option>Item <span data-bind="text: name"></span></option>
</select>
To handle this, you can use the containerless syntax, which is based on comment tags.
<select data-bind="foreach: items">
<option>Item <!--ko text: name--><!--/ko--></option>
</select>
The <!--ko--> and <!--/ko--> comments act as start/end markers, defining a "virtual element" that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.
IE 6 has a strange quirk whereby it sometimes ignores whitespace that immediately follows an empty span. This has nothing directly to do with Knockout, but in case you do want to write:
Welcome, `<span data-bind="text: userName"></span>` to our web site.
... and IE 6 renders no whitespace before the words to our web site, you can avoid the problem by putting any text into the <span>, e.g.:
Welcome, <span data-bind="text: userName"> </span> to our web site.
Other browsers, and newer versions of IE, don't have this quirk.
The textInput binding links a text box (<input>) or text area (<textarea>) with a viewmodel property, providing two-way updates between the viewmodel property and the element's value. Unlike the value binding, textInput provides instant updates from the DOM for all types of user input, including autocomplete, drag-and-drop, and clipboard events.
Main Parameter
KO sets the element's text content to your parameter value. Any previous value will be overwritten.
If this parameter is an observable value, the binding will update the element's value whenever the observable value changes. If the parameter isn't observable, it will only set the element's value once and will not update it again later.
If you supply something other than a number or a string (e.g., you pass an object or an array), the displayed text will be equivalent to yourParameter.toString() (that's usually not very useful, so it's best to supply string or numeric values).
Whenever the user edits the value in the associated form control, KO will update the property on your view model. KO will always attempt to update your view model when the value has been modified by the user or any DOM events.
Additional parameters
textInput vs value bindingAlthough the value binding can also perform two-way binding between text boxes and viewmodel properties, you should prefer textInput whenever you want immediate live updates. The main differences are:
Immediate updates
value, by default, only updates your model when the user moves focus out of the text box. textInput updates your model immediately on each keystroke or other text entry mechanism (such as cutting or dragging text, which don't necessarily raise any focus change events).
Browser event quirks handling
Browsers are highly inconsistent in the events that fire in response to unusual text entry mechanisms such as cutting, dragging, or accepting autocomplete suggestions. The value binding, even with extra options such as valueUpdate: afterkeydown to get updates on particular events, does not cover all text entry scenarios on all browsers.
The textInput binding is specifically designed to handle a wide range of browser quirks, to provide consistent and immediate model updates even in response to unusual text entry methods.
Don't try to use the value and textInput bindings together on the same element, as that won't achieve anything useful.
Note: This throttle API is deprecated as of Knockout 3.1.0. Please use the rateLimit extender for similar functionality.
Normally, computed observables are re-evaluated synchronously, as soon as each of their dependencies change. The throttle extender, however, causes a computed observable to delay re-evaluation until its dependencies have stopped changing for a specified period of time. Throttled computed observables therefore update asychronously.
The main uses cases for throttling are:
You'll find examples of these below.
Consider the computed observable in the following code:
var name = ko.observable('Bert');
var upperCaseName = ko.computed(function() {
return name().toUpperCase();
});
Normally, if you update name as follows:
name('The New Bert');
... then upperCaseName will be recomputed immediately, before your next line of code runs. But if you had instead defined upperCaseName using throttle as follows:
var upperCaseName = ko.computed(function() {
return name().toUpperCase();
}).extend({ throttle: 500 });
... then upperCaseName would not be recomputed immediately when name changes --- instead, it would wait for 500 milliseconds (half a second) before recomputing its value and then notifying any associated UI. Each time name changes, that timeout is reset back to zero, so the re-evaluation only occurs once name has stopped changing for at least half a second.
In this live example, there's an instantaneousValue observable that reacts immediately when you press a key. This is then wrapped inside a throttledValue computed observable that's configured to react only when you stop typing for at least 400 milliseconds.
Try it:
The following model represents data that you could render as a paged grid:
function GridViewModel() {
this.pageSize = ko.observable(20);
this.pageIndex = ko.observable(1);
this.currentPageData = ko.observableArray();
// Query /Some/Json/Service whenever pageIndex or pageSize changes,
// and use the results to update currentPageData
ko.computed(function() {
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this);
}
Because the ko.computed evaluates both pageIndex and pageSize, it becomes dependent on both of them. So, this code will use jQuery's $.getJSON function to reload currentPageData when the GridViewModel is first instantiated and whenever the pageIndex or pageSize properties are later changed.
This is very simple and elegant (and it's trivial to add yet more observable query parameters that also trigger a refresh automatically whenever they change), but there is a potential efficiency problem. What if you want to change both pageIndex and pageSize at once? You might add the following function to GridViewModel:
this.setPageSize = function(newPageSize) {
// Whenever you change the page size, we always reset the page index to 1
this.pageSize(newPageSize);
this.pageIndex(1);
}
The problem is that this will cause two simultaneous Ajax requests: the first one will start when you update pageSize, and the second one will start immediately afterwards when you update pageIndex. This is a waste of bandwidth and server resources, and a source of unpredictable race conditions.
Throttling is an elegant solution. You can add an arbitrarily short but nonzero throttle timeout (e.g., 1 millisecond), and then any sequence of synchronous changes to dependencies will only trigger one re-evaluation of your computed observable. For example,
ko.computed(function() {
// This evaluation logic is exactly the same as before
var params = { page: this.pageIndex(), size: this.pageSize() };
$.getJSON('/Some/Json/Service', params, this.currentPageData);
}, this).extend({ throttle: 1 });
Now you can update pageIndex and pageSize as many times as you like, and the Ajax call will only happen once at the end of that sequence. It doesn't matter if your thread continually makes changes for longer than 1 millisecond, because re-evaluation won't start until you release your thread back to the JavaScript runtime.
The uniqueName binding ensures that the associated DOM element has a nonempty name attribute. If the DOM element did not have a name attribute, this binding gives it one and sets it to some unique string value.
You won't need to use this often. It's only useful in a few rare cases, e.g.:
Other technologies may depend on the assumption that certain elements have names, even though names might be irrelevant when you're using KO. For example, jQuery Validation currently will only validate elements that have names. To use this with a Knockout UI, it's sometimes necessary to apply the uniqueName binding to avoid confusing jQuery Validation. See an example of using jQuery Validation with KO.
IE 6 does not allow radio buttons to be checked if they don't have a name attribute. Most of the time this is irrelevant because your radio button elements will have name attributes to put them into mutually-exclusive groups. However, just in case you didn't add a name attribute because it's unnecessary in your case, KO will internally use uniqueName on those elements to ensure they can be checked.
<input data-bind="value: someModelProperty, uniqueName: true" />
Main parameter
Pass true (or some value that evaluates as true) to enable the uniqueName binding, as in the preceding example.
Additional parameters
None, other than the core Knockout library.
In most cases, data-bind attributes provide a clean and succinct way to bind to a view model. However, event handling is one area that can often result in verbose data-bind attributes, as anonymous functions were typically the recommended techinique to pass arguments. For example:
<a href="#" data-bind="click: function() { viewModel.items.remove($data); }">
remove
</a>
As an alternative, Knockout provides two helper functions that allow you to identify the data associated with a DOM element:
ko.dataFor(element) - returns the data that was available for binding against the elementko.contextFor(element) - returns the entire binding context that was available to the DOM element.These helper functions can be used in event handlers that are attached unobtrusively using something like jQuery's bind or click. The above function could be attached to each link with a remove class like:
$(".remove").click(function () {
viewModel.items.remove(ko.dataFor(this));
});
Better yet, this techinique could be used to support event delegation. jQuery's live/delegate/on functions are an easy way to make this happen:
$(".remove").live("click", function() {
viewModel.items.remove(ko.dataFor(this));
});
Now, a single event handler is attached at a higher level and handles clicks against any links with the remove class. This method has the added benefit of automatically handling additional links that are dynamically added to the document (perhaps as the result of an item being added to an observableArray).
This example shows "add" and "remove" links on multiple levels of parents and children with a single handler attached unobtrusively for each type of link.
No matter how nested the links become, the handler is always able to identify and operate on the appropriate data. Using this techinique, we can avoid the overhead of attaching handlers to each individual link and can keep the markup clean and concise.
Note: The textInput binding can be used in many places instead of the value binding, providing broader support for many edge
cases and textInput update the observables on a per-character change (as opposed to the default of blur for the value binding).
The value binding links the associated DOM element's value with a property on your view model. This is typically useful with form elements such as <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.
Note: If you're working with checkboxes or radio buttons, use the checked binding to read and write your element's checked state, not the value binding.
Main parameter
KO sets the element's value property to your parameter value. Any previous value will be overwritten.
If this parameter is an observable value, the binding will update the element's value whenever the value changes. If the parameter isn't observable, it will only set the element's value once and will not update it again later.
If you supply something other than a number or a string (e.g., you pass an object or an array), the displayed text will be equivalent to yourParameter.toString() (that's usually not very useful, so it's best to supply string or numeric values).
Whenever the user edits the value in the associated form control, KO will update the property on your view model. KO will always attempt to update your view model when the value has been modified and a user transfers focus to another DOM node (i.e., on the change event), but you can also trigger updates based on other events by using the valueUpdate parameter described below.
Additional parameters
valueUpdate
If your binding also includes a parameter called valueUpdate, this defines additional browser events KO should use to detect changes besides the change event. The following string values are the most commonly useful choices:
"input" - updates your view model when the value of an <input> or <textarea> element changes. Note that this event is only raised by reasonably modern browsers (e.g., IE 9+)."keyup" - updates your view model when the user releases a key"keypress" - updates your view model when the user has typed a key. Unlike keyup, this updates repeatedly while the user holds a key down"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.Of these options, "input" is the best choice if you want to keep your view model updated in real-time, and you only need to support reasonably modern browsers such as IE 9+ (whereas "afterkeydown" is a good choice for older browsers). For example:
<p>Your value: <input data-bind="value: someValue, valueUpdate: 'input'" /></p>
<p>You have typed: <span data-bind="text: someValue"></span></p> <!-- updates in real-time -->
var viewModel = {
someValue: ko.observable("edit me")
};
valueAllowUnset
See Note 1 below. Note that valueAllowUnset is only applicable when using value to control selection on a <select> element. On other elements it has no effect.
<select> elements)Knockout has special support for drop-down lists (i.e., <select> elements). The value binding works in conjunction with the options binding to let you read and write values that are arbitrary JavaScript objects, not just string values. This is very useful if you want to let the user select from a set of model objects. For examples of this, see the options binding or for handling multi-select lists, see the documentation for the selectedOptions binding.
You can also use the value binding with a <select> element that does not use the options binding. In this case, you can choose to specify your <option> elements in markup or build them using the foreach or template bindings. You can even nest options within <optgroup> elements and Knockout will set the selected value appropriately.
valueAllowUnset with <select> elementsNormally, when you use the value binding on a <select> element, it means that you want the associated model value to describe which item in the <select> is selected. But what happens if you set the model value to something that has no corresponding entry in the list? The default behavior is for Knockout to overwrite your model value to reset it to whatever is already selected in the dropdown, thereby preventing the model and UI from getting out of sync.
However, sometimes you might not want that behavior. If instead you want Knockout to allow your model observable to take values that have no corresponding entry in the <select>, then specify valueAllowUnset: true. In this case, whenever your model value cannot be represented in the <select>, then the <select> simply has no selected value at that time, which is visually represented by it being blank. When the user later selects an entry from the dropdown, this will be written to your model as usual. For example:
<p>
Select a country:
<select data-bind="options: countries,
optionsCaption: 'Choose one...',
value: selectedCountry,
valueAllowUnset: true"></select>
</p>
var viewModel = {
countries: ['Japan', 'Bolivia', 'New Zealand'],
selectedCountry: ko.observable('Latvia')
};
In the above example, selectedCountry will retain the value 'Latvia', and the dropdown will be blank, because there is no corresponding option.
If valueAllowUnset had not been enabled, then Knockout would have overwritten selectedCountry with undefined, so that it would match the value of the 'Choose one...' caption entry.
If you use value to link a form element to an observable property, KO is able to set up a 2-way binding so that changes to either affect the other.
However, if you use value to link a form element to a non-observable property (e.g., a plain old string, or an arbitrary JavaScript expression), KO will do the following:
If you reference a simple property, i.e., it is just a regular property on your view model, KO will set the form element's initial state to the property value, and when the form element is edited, KO will write the changes back to your property. It cannot detect when the property changes (because it isn't observable), so this is only a 1-way binding.
If you reference something that is not a simple property, e.g., the result of a function call or comparison operation, KO will set the form element's initial state to that value, but it will not be able to write any changes back when the user edits the form element. In this case it's a one-time-only value setter, not an ongoing binding that reacts to changes.
Example:
<!-- Two-way binding. Populates textbox; syncs both ways. -->
<p>First value: <input data-bind="value: firstValue" /></p>
<!-- One-way binding. Populates textbox; syncs only from textbox to model. -->
<p>Second value: <input data-bind="value: secondValue" /></p>
<!-- No binding. Populates textbox, but doesn't react to any changes. -->
<p>Third value: <input data-bind="value: secondValue.length > 8" /></p>
var viewModel = {
firstValue: ko.observable("hello"), // Observable
secondValue: "hello, again" // Not observable
};
The visible binding causes the associated DOM element to become hidden or visible according to the value you pass to the binding.
Main parameter
When the parameter resolves to a false-like value (e.g., the boolean value false, or the numeric value 0, or null, or undefined), the binding sets yourElement.style.display to none, causing it to be hidden. This takes priority over any display style you've defined using CSS.
When the parameter resolves to a true-like value (e.g., the boolean value true, or a non-null object or array), the binding removes the yourElement.style.display value, causing it to become visible.
Note that any display style you've configured using CSS will then apply (so CSS rules like display:table-row work fine in conjunction with this binding).
If this parameter is an observable value, the binding will update the element's visibility whenever the value changes. If the parameter isn't observable, it will only set the element's visibility once and will not update it again later.
Additional parameters
You can also use a JavaScript function or arbitrary JavaScript expression as the parameter value. If you do, KO will run your function/evaluate your expression, and use the result to determine whether to hide the element.
For example,
The with binding creates a new binding context, so that descendant elements are bound in the context of a specified object.
Of course, you can arbitrarily nest with bindings along with the other control-flow bindings such as if and foreach.
Here is a very basic example of switching the binding context to a child object. Notice that in the data-bind attributes, it is not necessary to prefix latitude or longitude with coords., because the binding context is switched to coords.
This interactive example demonstrates that:
with binding will dynamically add or remove descendant elements depending on whether the associated value is null/undefined or not$parent and root.
Main parameter
The object that you want to use as the context for binding descendant elements.
If the expression you supply evaluates to null or undefined, descendant elements will not be bound at all, but will instead be removed from the document.
If the expression you supply involves any observable values, the expression will be re-evaluated whenever any of those observables change. Then, descendant elements will be cleared out, and a new copy of the markup will be added to your document and bound in the context of the new evaluation result.
Additional parameters
Just like other control flow elements such as if and foreach, you can use with without any container element to host it. This is useful if you need to use with in a place where it would not be legal to introduce a new container element just to hold the with binding. See the documentation for if or foreach for more details.
Example:
<ul>
<li>Header element</li>
<!-- ko with: outboundFlight -->
...
<!-- /ko -->
<!-- ko with: inboundFlight -->
...
<!-- /ko -->
</ul>
The <!-- ko --> and <!-- /ko --> comments act as start/end markers, defining a "virtual element" that contains the markup inside. Knockout understands this virtual element syntax and binds as if you had a real container element.