A Beginners Guide to KnockoutJS: Basics and Observables
Almost everyone dealing with web technologies knows jQuery, or at least has heard about it. Its unmatched simplicity and conciseness makes the lives of millions of web developers all over the world much easier–and that’s fantastic.
Unfortunately jQuery is not solution for every problem. As soon as you decide to create some more complex web apps you encounter a problem – there is no easy way to make your UI and data communicate each other dynamically. With the low-level DOM manipulation and events handling provided by jQuery this is fairly hard to achieve. You need a library providing you with more sophisticated way of communication between your UI and the underlying data model.
And here is where Knockout comes in. Knockout is a JavaScript library which helps the creation of rich, desktop-like web UIs. It simplifies user interactions and makes interfaces fully responsive to any data source changes. Knockout provides a simple two-way binding mechanism to link a data model to an UI, thus making synchronization between them a breeze.
Although you will need to use Knockout with jQuery at the same time, in some cases like animated transitions, Knockout itself doesn’t depend on it. Another thing you need to understand is that Knockout doesn’t compete with jQuery – they both do excellent job; each one in its own direction. As you will see if you want to get the most benefits you should use them together.
In this tutorial, we start with the core concepts and capabilities of Knockout. In part two, we’ll go deeper exploring the built-in bindings and how to use them. And in the finale, we’ll go through some advanced features and techniques, such as extended observables and how to create your own custom bindings. Let’s get started!
Basic Concepts
Before we go through the code examples, first you may need to grasp some basic concepts. Knockout implements Model-View-View Model (MVVM) design pattern for JavaScript. In this pattern your application is split into three parts:
A model that holds your application’s data. This can be data entered by users or JSON data fetched from a web server.
A view that serves as a connector and communication layer between Model and View. It holds data and operations for manipulating this data and display it in the UI. Every time when data model is changed corresponded UI parts updates, reflecting these changes. View Model in your application is represented by JavaScript code.
A view that refers to all UI elements in your application. It is a representation of the structure and appearance for given UI. The view is responsible for displaying data and accepting user input. View is represented by HTML/CSS code in your application.
They are three core concepts upon Knockout is built:
1. Declarative Bindings: These allow you to connect parts of your UI to your data model in a simple and convenient way. When use JavaScript directly to manipulates DOM this may cause broken code if you later change the DOM hierarchy or element IDs. With declarative bindings even if you change the DOM all bound pieces stay connected. You can bind data to a DOM by simply including a data-bind attribute to any DOM element.
2. Dependency Tracking: Thankfully to the bindings and special type of variables called observables every time when your model data has changed all parts associated with it automatically being updated. No need to worry about adding event handlers and listeners. All that extra work is performed internally by Knockout and observables, which notify listeners when underlying values have changed.
3. Templating: This comes in handy when your application becomes more complex and you need a way to display a rich structure of view model data, thus keeping your code simple. Knockout has a native, built-in template engine which you can use right away. But if you want, a third-party template engine, like jquery.tmpl or Underscore, also can be used.
Don’t worry if all this theory sounds obscure to you. When we go through the tutorial and the code examples everything will become clearer.
Getting Started
Before we dive into Knockout you need to download and reference the library in your HTML document.
<script type='text/javascript' src='knockout-2.0.0.js'></script>
To keep your code separate from your presentation is better to create a JavaScript file to hold all application code. And because we will use jQuery in some cases you need to reference it too.
<script type='text/javascript' src='jquery-1.7.1.min.js'></script>
<script type='text/javascript' src='knockout-2.0.0.js'></script>
<script type='text/javascript' src='application.js'></script>
This is considered as best practice but for training purpose and to make things easier you can put the JavaScript code in the same document by either including it in the head tag or place it bellow your markup.
Now, to create a view model just declare any JavaScript object like this:
function viewModel() {
// Your code here
};
The data-bind attribute (explained later) isn’t native to HTML, and the browser doesn’t know what it means. So in order to take effect Knockout has to be activated by inserting ko.applyBindings()
function at the end of the script. Also if you use external JavaScript file or your script is placed in the head tag of your document you need to wrap the Knockout code in a jQuery ready function in order to work properly. Here is the basic template to start:
$(document).ready(function(){
function viewModel() {
// Your code here
};
ko.applyBindings(new viewModel());
});
Calling the ko.applyBindings()
method and passing in our view model tells Knockout to bind the specified model to our UI. You can even provide a DOM element if you only want to bind this view model to one part of your overall UI. ko.applyBindings()
takes two parameters. The first parameter says what view model object you want to use with the declarative bindings it activates. The second parameter is optional and it defines which part of the document you want to search for data-bind attributes. For example, ko.applyBindings(viewModel, document.getElementById('container'))
will restrict the activation to the element with ID container and its descendants. This is useful if you want to have multiple view models and associate each with a different region of the page.
How It Works
With Knockout, you can bind data to a DOM element by including a data-bind attribute in the markup which specifies the data-binding to perform. The code never has any reference to the DOM structure so you can freely change the HTML without breaking your bindings. In the following example we add text data-bind attribute to span
element like this:
// syntax: data-bind="bindingName: bindingValue"
<p>The day of the week is <span data-bind="text: dayOfWeek"></span>. It's time for <span data-bind="text: activity"></span></p>
Then if we want to make the value of text to updates dynamically then we have to declare it in our view model as an observable.
function viewModel() { this.dayOfWeek = ko.observable('Sunday'); this.activity = ko.observable('rest'); }; ko.applyBindings(new viewModel());
This will output "The day of the week is Sunday. It’s time for rest".
Observables
Knockout implements observable properties by wrapping object properties with a custom function named ko.observable()
.
this.property = ko.observable('value')
Observables are set as functions. As such you can use them in the following manner:
// To read the observable's current value, just call the observable with no parameters.
// The following will return Sunday
this.dayOfWeek()
// To write a new value to the observable, call the observable and pass the new value as a parameter.
// The following will change the day of week to Monday
this.dayOfWeek('Monday')
// To write values to multiple observable properties on a model object, you can use chaining syntax.
this.dayOfWeek('Monday').activity('work')
Knockout doesn’t require you to use observable properties. If you want DOM elements to receive values once but then not be updated when the values in the source object change, simple objects will be sufficient. However, if you want your source object and target DOM elements to stay in sync – two-way binding – then you’ll want to consider using observable properties.
In some cases you may need to combine the values of two or more observables into one new value. This can be done with so-called computed observables. Computed observables are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. The computed property automatically updates when any of the observables it depends on for its evaluation change. In the following example the computed observable named fullDate
will updates every time when one or more of the day
, month
and year
observables change.
<p>Day: <input data-bind="value: day" /></p>
<p>Month: <input data-bind="value: month" /></p>
<p>Year: <input data-bind="value: year" /></p>
<p>The current date is <span data-bind="text: fullDate"></span></p>
function viewModel() {
this.day = ko.observable('24');
this.month = ko.observable('02');
this.year = ko.observable('2012');
this.fullDate = ko.computed(function() {
return this.day() + "/" + this.month() + "/" + this.year();
},this);
};
ko.applyBindings(new viewModel());
The ko.computed()
takes a second parameter this
. Without passing it in, it would not have been possible to refer to this.day()
, this.month()
or this.year()
. In order to simplify things you can create a variable self
, thus avoiding the addition of the second parameter. From now on we will use this approach in the code examples.
function viewModel() {
var self = this;
self.day = ko.observable('24');
self.month = ko.observable('02');
self.year = ko.observable('2012');
self.fullDate = ko.computed(function() {
return self.day() + "/" + self.month() + "/" + self.year();
});
};
ko.applyBindings(new viewModel());
When you dealing with one object you can easily track any changes to it by turn it into an observable. But what if you have multiple objects? In such cases Knockout has a special object called ko.observableArray()
, which can detect and respond to changes of a collection of things. This makes possible to display and/or edit multiple values, for example, when you need repeated sections of UI to appear and disappear as items are added and removed.
You should bear in mind that an observable array tracks which objects are in the array, not the state of those objects. Simply putting an object into an observable array doesn’t make all of that object’s properties themselves observable. If you wish you can make those properties observable, but that’s totally up to you. An observable array just tracks which objects it holds, and notifies listeners when objects are added or removed.
this.property = ko.observableArray();
When you create an observable array you can leave it empty or populate it with some initial values. In the following example we create an observable array populated with the days of the week:
<p>Today is <span data-bind="text: daysOfWeek()[0]"></span></p>
function viewModel() {
var self = this;
self.daysOfWeek = ko.observableArray([
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
]);
alert("The week has " + self.daysOfWeek().length + " days");
};
ko.applyBindings(new viewModel());
As you can see, to read and write Knockout array you can use any native JavaScript functions. But Knockout has its own equivalent functions which syntax is a little bit more convenient:
array().push('Some value'); // native JavaScript
array.push('Some value'); // Knockout
For the full list of available functions you can check out the documentation.
If you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like JavaScript Programming for the Web.