This lesson is designed to be a high-level survey of Knockout.js’ main components. By implementing a concrete sample application, we’ll see how Knockout’s ViewModel, view, observables, and bindings interact to create a dynamic user interface.
First, we’ll create a simple HTML page to hold all of our code, then we’ll define a ViewModel object, expose some properties, and even add an interactive binding so that we can react to user clicks.
Download Knockout.js
Before we start writing any code, download the latest copy of Knockout.js from the downloads page at GitHub.com. As of this writing, the most recent version is 2.1.0. After that, we’re ready to add the library to an HTML page.
The HTML
Let’s start with a standard HTML page. In the same folder as your Knockout.js library, create a new file called index.html, and add the following. Make sure to change knockout-2.1.0.js to the file name of the Knockout.js library you downloaded.
Sample code: item1.htm
<html lang='en'> <head> <title>Hello, Knockout.js</title> <meta charset='utf-8' /> <link rel='stylesheet' href='style.css' /> </head> <body> <h2> <p>Bill's Shopping Cart</p> <script src='knockout-2.1.0.js'></script> </body> </html>
This is a basic HTML 5 webpage that includes the Knockout.js library at the bottom of <body>
; although, like any external script, you can include it anywhere you want (inside <head>
is the other common option). The style.css style sheet isn’t actually necessary for any of the examples in this series, but it will make them much easier on the eyes. It can be found in Appendix A, or downloaded from https://bitbucket.org/syncfusion/knockoutjs_succinctly. If you open the page in a web browser, you should see the following:
Defining the ViewModel
Since we’re not working with any persistent data yet, we don’t have a model to work with. Instead we’ll skip right to the ViewModel. Until Lesson 7:, we’re really just using a View-ViewModel pattern.
Remember, a ViewModel is a pure JavaScript representation of your model data. To start out, we’ll just use a native JavaScript object as our ViewModel. Underneath the <script> tag that includes Knockout.js, add the following:
<script> var personViewModel = { firstName: "John", lastName: "Smith" }; ko.applyBindings(personViewModel); </script> </body>
This creates a “person” named John Smith, and the ko.applyBindings()
method tells Knockout.js to use the object as the ViewModel for the page.
Of course, if you reload the page, it will still display “Bill’s Shopping Cart.” For Knockout.js to update the view based on the ViewModel, we need to bind an HTML element to the personViewModel
object.
Binding an HTML Element
Knockout.js uses a special data-bind
attribute to bind HTML elements to the ViewModel. Replace Bill in the <p> tag with an empty <span> element, as follows:
<p><span data-bind='text: firstName'></span>'s Shopping Cart</p>
The value of the data-bind attribute tells Knockout.js what to display in the element. In this case, the text
binding tells Knockout.js to display the firstName property of the ViewModel. Now, when you reload the page, Knockout.js will replace the contents of the <span> with personViewModel.firstName. As a result, you should see “John’s Shopping Cart” in your browser:
Similarly, if you change the data-bind attribute to text: lastName, it will display “Smith’s Shopping Cart.” As you can see, binding an element is really just defining an HTML template for your ViewModel.
Observable Properties
So, we have a ViewModel that can be displayed in an HTML element, but watch what happens when we try to change the property. After calling ko.applyBindings()
, assign a new value to personViewModel.firstName:
ko.applyBindings(personViewModel); personViewModel.firstName = "Ryan";
Knockout.js won’t automatically update the view, and the page will still read “John’s Shopping Cart.” This is because we haven’t exposed the firstName
property to Knockout.js. Any properties that you want Knockout.js to track must be observable. We can make our ViewModel’s properties observable by changing personViewModel to the following:
var personViewModel = { firstName: ko.observable("John"), lastName: ko.observable("Smith") };
Instead of directly assigning values to firstName
and lastName
, we use ko.observable() to add the properties to Knockout.js’ automatic dependency tracker. When we change the firstName property, Knockout.js should update the HTML element to match:
ko.applyBindings(personViewModel); personViewModel.firstName("Ryan");
Accessing Observables
You’ve probably noticed that observables are actually functions—not variables. To get the value of an observable, you call it without any arguments, and to set the value, you pass the value as an argument. This behavior is summarized as follows:
-
Getting: Use
obj.firstName()
instead of obj.firstName -
Setting: Use
obj.firstName("Mary")
instead of obj.firstName = "Mary"
Adapting to these new accessors can be somewhat counterintuitive for beginners to Knockout.js. Be very careful not to accidentally assign a value to an observable property with the =
operator. This will overwrite the observable, causing Knockout.js to stop automatically updating the view.
Using Custom Objects
Our generic personViewModel
object and its observable properties work just fine for this simple example, but remember that ViewModels can also define methods for interacting with their data. For this reason, ViewModels are often defined as custom classes instead of generic JavaScript objects. Let’s go ahead and replace personViewModel with a user-defined object:
function PersonViewModel() { this.firstName = ko.observable("John"); this.lastName = ko.observable("Smith"); }; ko.applyBindings(new PersonViewModel());
This is the canonical way to define a ViewModel and activate Knockout.js. Now, we can add a custom method, like so:
function PersonViewModel() { this.firstName = ko.observable("John"); this.lastName = ko.observable("Smith"); this.checkout = function() { alert("Trying to check out!"); }; };
Combining data and methods in a single object is one of the defining features of the MVVM pattern. It provides an intuitive way to interact with data. For example, when you’re ready to check out simply call the checkout()
method on the ViewModel. Knockout.js even provides bindings to do this directly from the view.
Interactive Bindings
Our last step in this lesson will be to add a checkout button to call the checkout()
method we just defined. This is a very brief introduction to Knockout.js’s interactive bindings, but it provides some useful functionality that we’ll need in the next lesson. Underneath the <p> tag, add the following button:
<button data-bind='click: checkout'>Checkout</button>
Instead of a text binding that displays the value of a property, the click
binding calls a method when the user clicks the element. In our case, it calls the checkout() method of our ViewModel, and you should see an alert message pop up.
Knockout.js’ full suite of interactive bindings will be covered in Lesson 6:.
Summary
This lesson walked through the core aspects of Knockout.js. As we’ve seen, there are three steps to setting up a Knockout.js-based web application:
- Creating a ViewModel object and registering it with Knockout.js.
- Binding an HTML element to one of the ViewModel’s properties.
- Using observables to expose properties to Knockout.js
You can think of binding view elements to observable properties as building an HTML template for a JavaScript object. After the template is set up, you can completely forget about the HTML and focus solely on the ViewModel data behind the application. This is the whole point of Knockout.js.
In the next lesson, we’ll explore the real power behind Knockout.js’ automatic dependency tracker by creating observables that rely on other properties, as well as observable arrays to hold lists of data.
This lesson represents a chapter from Knockout Succinctly, a free eBook from the team at Syncfusion.
Comments