Object JavaScript – Bindings With MVVM in Knockout.js

knockoutIn our previous post Dynamic UI Using Observables with MVVM Using Knockout.js, you learned how you get started with Knockout.js and how you can detect and respond to changes on one object using observables.

Knockout provides ways to bind the data you specify in the data-bind attribute to the element. You can apply bindings to the text and appearance, use them in the logic you use to display items, and working with form fields.

In addition, you can create your own custom bindings.

Let’s see how.

Controlling Text, Appearance Using Bindings

You can  bind the the firstName property in the viewmodel to the text in the strong element.

<strong data-bind="text: firstName">

The text binding causes the associated DOM element to display the text value of your parameter.

You typically use the text binding with elements like <span> or <em> that traditionally display text, but technically you can use it with any element.

Other bindings give you access to the element.

  • visible. The visible binding causes the associated DOM element to become hidden or visible according to the value you pass to the binding.
  • html. 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.
  • css. 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.
  • style. 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.
  • attr. 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.

Show Hide Sample

Here’s a sample showing how each visible can be used with click, disable, enable bindings:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Show Hide</title>
</head>
<body>
<div data-bind="visible: onoff">Show Me</div>
<button data-bind="click: showMe, disable: onoff">Show Text</button>
<button data-bind="click: hideMe, enable: onoff">Hide Text</button>
<script src="Scripts/knockout-2.2.1.debug.js"></script>
<script>
var viewModel = function () {
this.onoff = ko.observable(true); // onoff is intially set to true
hideMe = function() {
this.onoff(false);
};
showMe = function () {
this.onoff(true);
};
}
ko.applyBindings(new viewModel());
</script>
</body>
</html>

CSS and HTML Sample

The following Knockout.js sample shows how you can use html, attr, and css bindings.

<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.redItem {
color: red;
}
.greenItem {
color: green;
}
</style>
</head>
<body>
<div data-bind="html: someHtml"></div>
<div>And a link <a data-bind="attr: { href: myHref }">#</a></div>
<div data-bind="css: profitStatus, text: currentProfit"></div>
<button data-bind="click: reviseProfit">Revise Profit</button>
<script src="Scripts/knockout-2.2.1.debug.js"></script>
<script>
var viewModel = function () {
this.someHtml = "Here is a <strong>bold</strong> text.";
this.myHref = "#";
this.currentProfit = ko.observable(150000);
this.profitStatus = ko.computed(function () {
return this.currentProfit() < 0 ? "redItem" : "greenItem";
}, this);
this.reviseProfit = function () {
this.currentProfit(50);
};
};
ko.applyBindings(new viewModel());
</script>
</body>
</html>

Control Flow Bindings

There are four bindings that help you with control flow. The foreach, if, ifnot, and with bindings provide ways for you to control what is displayed and how the data are displayed.

foreach Control Flow Binding

foreach. 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.

The foreach binding is covered in the next post, Dynamic UI With MVVM Using ObservableArray in Knockout.js, that is tied to observableArrays.

if and notif Control Flow Bindings

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).

It is a lot like the visible binding in functionality, except that with visible the markup remains in the DOM and a CSS style applied to hide the element. The if binding adds and removes the markup in your DOM.

The ifnot binding is exactly the same as the if binding, except that it inverts the result of whatever expression you pass to it.

Here’s an example.

<!DOCTYPE html>
<html>
<head>
<title>Control Flow Bindings</title>
</head>
<body>
<label>
<input type="checkbox" data-bind="checked: displayMessage" />
Display message</label>
<div data-bind="if: displayMessage">There's something important here.</div>
<script src="Scripts/knockout-2.2.1.debug.js"></script>
<script>
ko.applyBindings({
displayMessage: ko.observable(false)
});
</script>
</body>
</html>

with Control Flow Binding

The with binding creates a new binding context, so that descendant elements are bound in the context of a specified object.

The following example, displays a product, along with related data that is nested:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<h1 data-bind="text: product"></h1>
<p data-bind="with: warehouse">
Warehouse Location: <span data-bind="text: location"></span>,
Quantity Available: <span data-bind="text: quanAvail"></span>
</p>
<script src="Scripts/knockout-2.2.1.debug.js"></script>
<script type="text/javascript">
ko.applyBindings({
product: "Widget",
warehouse: {
location: "3D1",
quanAvail: 6
}
});
</script>
</body>
</html>

Binding to Control Types

The following is an example of binding view model properties to a range of HTML control types. This is from the Knockout Control types example in the Knockoutjs documentation.

<!DOCTYPE html>
<html>
<head>
<title>Binding HTML Controls</title>
</head>
<body>
<div class="readout">
<h3>What's in the model?</h3>
<table>
<tr>
<td class="label">Text value:</td>
<td data-bind="text: stringValue"></td>
</tr>
<tr>
<td class="label">Password:</td>
<td data-bind="text: passwordValue"></td>
</tr>
<tr>
<td class="label">Bool value:</td>
<td data-bind='text: booleanValue() ? "True" : "False"'></td>
</tr>
<tr>
<td class="label">Selected option:</td>
<td data-bind="text: selectedOptionValue"></td>
</tr>
<tr>
<td class="label">Multi-selected options:</td>
<td data-bind="text: multipleSelectedOptionValues"></td>
</tr>
<tr>
<td class="label">Radio button selection:</td>
<td data-bind="text: radioSelectedOptionValue"></td>
</tr>
</table>
</div>
<h3>HTML controls</h3>
<table>
<tr>
<td class="label">Text value (updates on change):</td>
<td><input data-bind="value: stringValue" /></td>
</tr>
<tr>
<td class="label">Text value (updates on keystroke):</td>
<td><input data-bind='value: stringValue, valueUpdate: "afterkeydown"' /> </td>
</tr>
<tr>
<td class="label">Text value (multi-line):</td>
<td><textarea data-bind="value: stringValue"> </textarea></td>
</tr>
<tr>
<td class="label">Password:</td>
<td><input type="password" data-bind="value: passwordValue" /></td>
</tr>
<tr>
<td class="label">Checkbox:</td>
<td><input type="checkbox" data-bind="checked: booleanValue" /></td>
</tr>
<tr>
<td class="label">Drop-down list:</td>
<td><select data-bind="options: optionValues, value: selectedOptionValue"> </select></td>
</tr>
<tr>
<td class="label">Multi-select drop-down list:</td>
<td><select multiple="multiple"
data-bind="options: optionValues, selectedOptions: multipleSelectedOptionValues">
</select></td>
</tr>
<tr>
<td class="label">Radio buttons:</td>
<td>
<label><input type="radio" value="Alpha"
data-bind="checked: radioSelectedOptionValue" />Alpha</label>
<label><input type="radio" value="Beta"
data-bind="checked: radioSelectedOptionValue" />Beta</label>
<label><input type="radio" value="Gamma"
data-bind="checked: radioSelectedOptionValue" />Gamma</label>
</td>
</tr>
</table>
<script type="text/javascript" src="Scripts/knockout-2.2.1.js"></script>
<script>
var viewModel = {
stringValue: ko.observable("Hello"),
passwordValue: ko.observable("mypass"),
booleanValue: ko.observable(true),
optionValues: ["Alpha", "Beta", "Gamma"],
selectedOptionValue: ko.observable("Gamma"),
multipleSelectedOptionValues: ko.observable(["Alpha"]),
radioSelectedOptionValue: ko.observable("Beta")
};
ko.applyBindings(viewModel);
</script>
</body>
</html>

Interesting parts to call out.

valueUpdate: “afterkeydown” provides the update to the viewmodel and to the observable elements after each key is pressed.

selectedOptions: multipleSelectedOptionValues provides the selected values.

and value attribute, checked bindings provide the value for the radio buttons.

Custom 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 Creating custom bindings in the Knockout documentation.

References

Getting Started with Knockout