Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying MASTERING KNOCKOUTJS
  • Table Of Contents Toc
MASTERING KNOCKOUTJS

MASTERING KNOCKOUTJS

By : Moran
4.7 (6)
close
close
MASTERING KNOCKOUTJS

MASTERING KNOCKOUTJS

4.7 (6)
By: Moran

Overview of this book

If you are an experienced JavaScript developer who is looking for new tools to build web applications and get an understanding of core elements and applications, this is the book for you. A basic knowledge of DOM, JavaScript, and KnockoutJS is assumed.
Table of Contents (11 chapters)
close
close
10
Index

The data-bind syntax

Knockout takes advantage of the HTML5 data-* attribute specification to define its data-bind attribute. Though all HTML attributes are necessarily strings, Knockout parses them as name:value pairs. The name refers to the binding handler to be used and the value refers to the value the binding will use:

<button data-bind="enable: canSave">Save</button>

The data-bind attribute can also contain multiple bindings separated by commas. This allows multiple properties to be bound on an element:

<input data-bind="value: firstName, enable: canEdit" />

In the preceding example, the enable binding uses canEdit as a value. The binding will set the disabled attribute on the button element when canEdit is false, and remove the disabled attribute when canEdit is true. If canEdit is an observable, the enable binding will update whenever canEdit is updated. If canEdit is a literal value, such as true, it will only use the value to set the initial state.

Enable is a one-way binding; it will update the element with changes from the value but it will not update the value with changes from the element. This is because when enable is being used to control the element, Knockout assumes that nothing will be programmatically updating the element. Updates should happen in the viewmodel, and binding handlers should be responsible for ensuring the view is kept in sync.

When users update the UI of data-bound input elements, those changes need to be synced to the viewmodel. This is done with two-way bindings, such as the value binding:

<input data-bind="value: firstName" />

This binding will set the initial value of the input element to the current value of the firstName property, and after that, it will ensure that any changes to either the element's value or the property cause the other to update. If the user types something into the input, the firstName property will receive the value. If the firstName property is updated programmatically, the input's value will be updated.

These are both examples of binding against a simple property on the viewmodel. This is the most common case, but Knockout supports more complex scenarios as well.

Note

For a complete list of the standard Knockout binding handlers, see the Knockout documentation (http://knockoutjs.com/documentation/introduction.html).

Binding with nested properties

In the previous example, Knockout parsed the binding value for the name of a property and looked for that property on the current viewmodel. You can also provide deep property references. Consider the following object:

var viewmodel = {
  user: {
    firstName: ko.observable('Tim'),
    age: ko.observable(27)
  }
};

We can bind directly against the firstName property of the viewmodel's user by using standard dot notation:

<input data-bind="value: user.firstName" />

Binding against functions

If you are using the click or event bindings to bind some UI event, the binding expects the property to be a function. Functions will receive the current model (the binding context) as their first parameter, and the JavaScript event as the second parameter (though you shouldn't need to do this very often).

In this example, the parent viewmodel receives the contact to be removed from the click binding because the foreach loop creates a nested binding context for each contact. The parent reference in the binding moves the context up to the parent viewmodel to get access to the remove function:

<ul data-bind="foreach: contacts">
    <li>
      <span data-bind="text: name"></span>
      <button data-bind="click: $parent.remove">Remove</button>
    </li>
</ul>

var ViewModel = function() {
    var self = this;
    self.contacts = ko.observableArray([{ name: 'Tim' }, { name: 'Bob' }]);
    self.remove = function (contact) {
         self.contacts.remove(contact);
    };
};

Binding with expressions

In addition to property references, Knockout also supports the use of JavaScript expressions as binding values. For bindings that expect true or false values, such as enable, we can use Boolean expressions to set them:

<button data-bind="enable: age > 18">Approve</button>

We can also use ternary expressions to control the result of the expression. This is useful in cases where Booleans are not expected, such as text bindings:

Old enough to Drink in the U.S. 
<span data-bind="text: age > 18 ? 'Yes' : 'No'"></span>

Now the span will have Yes as content.

Both forms of expressions will use dependency tracking to rerun if they read from an observable the first time they are run. If age was an observable value, we could update it and the element's binding would re-evaluate the expression, changing the text or enabled state if the result changed.

Binding with function expressions

The last method to set binding values is by using functions. You can call a function by referencing it in the binding:

<button data-bind="enable: canApprove(age)">Approve</button>

You can also write an anonymous function as a string directly in the binding. When creating a function for the click binding, the parameters are the binding context (viewmodel) and the JavaScript click event. If you bind against a viewmodel function using its property name, it would receive the same parameters:

<button data-bind="text: 
function(data) { console.log(data.age)  }">Log Age</button>

Though this is possible, I wouldn't encourage it. It places logic directly in the view instead of in the viewmodel where it belongs. You should only use this last method in very special cases. It's much better to place the method on the viewmodel and just use a property reference.

Using parentheses in bindings

It can be confusing trying to figure out when to use parentheses in bindings to use an observable as a value. Knockout tries to be helpful by not requiring the parentheses in simple binding expressions like this one:

<input data-bind="value: firstName" />

In this example, the firstName property could be either an observable or a literal value, and it would work just fine. However, there are two cases when the parentheses are needed in bindings: when binding against a nested property and when binding with an expression. Consider the following viewmodel:

var viewmodel = {
  user: ko.observable({
    firstName: ko.observable('Tim'),
    age: ko.observable(27)
  })
};

The user object here is an observable property, as are each of its properties. If we wanted to write the same binding now, it would need to include parentheses on the user function but still not on the firstName property:

<input data-bind="value: user().firstName" />

In cases where we are binding directly against a property, the parentheses of that property are never needed. This is because Knockout is smart enough to understand how to access the value of the observable that it is given in bindings.

However, if we are binding against an expression, they are always needed:

<button data-bind="enable: user().age > 18">Approve</button>
<button data-bind="enable: user().age() > 18">Approve</button>

Neither of these bindings will cause errors, but the first one will not work as expected. This is because the first expression will try to evaluate on the age observable itself (which is a function, not a number) instead of the observable's value. The second one correctly compares the value of the observable to 18, producing the expected result.

Debugging with ko.toJSON

Because ko.toJSON accepts the spaces argument for JSON.stringify, you can use it in a text binding to get a live copy of your viewmodel with nice, readable formatting:

<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

The cp1-databind branch has an interactive example of each of these bindings.

CONTINUE READING
83
Tech Concepts
36
Programming languages
73
Tech Tools
Icon Unlimited access to the largest independent learning library in tech of over 8,000 expert-authored tech books and videos.
Icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Icon 50+ new titles added per month and exclusive early access to books as they are being written.
MASTERING KNOCKOUTJS
notes
bookmark Notes and Bookmarks search Search in title playlist Add to playlist font-size Font size

Change the font size

margin-width Margin width

Change margin width

day-mode Day/Sepia/Night Modes

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY

Submit Your Feedback

Modal Close icon
Modal Close icon
Modal Close icon