Book Image

KnockoutJS by Example

By : Adnan Jaswal
Book Image

KnockoutJS by Example

By: Adnan Jaswal

Overview of this book

KnockoutJS By Example is a project-based guide that introduces the key features and concepts of knockout.js. It helps you create an application skeleton and a Hello World application. You will develop a To-Do list application that aims to show the basic features of knockout.js in action, such as data binding and observables, following which you will develop a dynamic online customer registration form that captures and validates customer information. This book will further walk you through developing a customer banking portal, which demonstrates the use of knockout.js with components such as navigation bars, tabs, carousels, master details view, panels, forms, and wizards. You will also discover how to use token-based authentication and authorization to secure the customer banking portal, and move on to creating an editable products grid with CRUD operations. Finally, you will explore how to use the Google Maps API with knockout.js. KnockoutJS By Example will not only leave you with a basic understanding of knockout.js fundamentals but also take you through some of the advanced features. It will help you get a web application up and ready instantly.
Table of Contents (17 chapters)
KnockoutJS by Example
Credits
About the Author
Acknowledgment
About the Reviewers
www.PacktPub.com
Preface
Index

Building the address book application


Now that we have a basic understanding of the design patterns we will be using and the key features of Knockout, let's dive into building our first application. Our first application is an address book, which is used to store and display contact details of your family and friends. The application lets you add a contact's name and phone number. The contacts are displayed in a table. This is a simple application that highlights some of the basic features that Knockout has to offer.

We will take an iterative approach in building this and all the other example applications in this book. The idea behind an iterative approach is to build the application in small portions. Each portion will deliver a subset of the features. We will continue to evolve the application until the full application is implemented.

A word on the development environment

You can use any Integrated Development Environment (IDE) of your choice or simply use a text editor like notepad or vi to develop the application. I recommend using an IDE as it increases developer productivity by many folds. I use an open source IDE called eclipse. You can find out more about eclipse at http://eclipse.org/.

Web applications are typically hosted on a web server. You can choose a web server that you are familiar with to host the example applications in this book. The two web server that I recommend are:

  • Apache HTTP Server: This is the most popular web server on the internet. You can find out more about Apache at http://httpd.apache.org/.

  • Node.js HTTP Server: Node.js has gained popularity in recent times. Find out more about Node.js at http://nodejs.org/.

You do not require a web server for developing a pure client-side web application using only HTML, JavaScript, and CSS. You can simply view the HTML files by opening them in a browser from your file system. Most examples in this book do not require a web server for development unless you are planning to host the applications or the application requires a server-side component such as a RESTful API endpoint.

Downloading the libraries

First, we need to download the libraries that we require. The two libraries we require are Knockout and jQuery.

Download Knockout from the Knockout's website at http://knockoutjs.com/. This should be a single JavaScript file.

Next, download jQuery from the jQuery's website at http://jquery.com/. This should also be a single JavaScript file.

Creating the skeleton

First, we will create the skeleton for our address book application. We will use this skeleton for all the example applications in this book.

Note

A skeleton is a high-level structure that compiles but does not provide any application features. The skeleton is iteratively evolved into a working application. The skeleton forms a template that provides the basic structure, which can be then used in other applications.

Let's create the folder structure for development by following these steps:

  1. Create the AddressBook folder. This is the main folder that houses our address book application.

  2. Add a WebContent folder under the AddressBook folder. This folder holds the content that gets published to the web.

  3. Add a javascript folder under the WebContent folder. As the folder name suggests, this folder will contain all our JavaScript files.

Now that we have the folder structure in place, let's add some files to our folders by following these steps:

  1. Add the Knockout library that you downloaded to the javascript folder.

  2. Add the JQuery library that you downloaded to the javascript folder.

  3. Create the addressbook.js file under the javascript folder.

  4. Create the addressbook.html file under the WebContent folder.

Following these steps should result a folder structure that looks similar to this:

Now that we have created the folder structure, we can add code to our HTML and JavaScript files. Open the addressbook.html file and add the following HTML code:

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html" />
    <title><!-- add title --></title>
    <!-- the jquery library -->
    <script type="text/javascript" src="javascript/jquery-2.1.3.min.js"></script>
    <!-- the knockout library -->
    <script type="text/javascript" src="javascript/knockout-3.2.0.js"></script>
    <!-- module for our application -->
    <script type="text/javascript" src="javascript/addressbook.js"></script>
  </head>
  <body>
    <!-- add body content -->
  </body>
</html>

The file in its current state does not do much. It references Knockout and jQuery libraries from our javascript folder. It also references our addressbook.js application module.

Tip

Any application modules, such as addressbook.js, should always be referenced after the Knockout and jQuery libraries. This is because the application module will use the ko and $ objects defined by these libraries. Make sure that the application module is referenced after these libraries if you get an error, stating that either ko or $ is undefined.

Open the addressbook.js file and add the following code; this code defines our empty AddressBook module:

/* Module for Address Book application */
var AddressBook = function () {

  /* add members here */

  var init = function () {
    /* add code to initialize this module */
  };

  /* execute the init function when the DOM is ready */
  $(init);
  
  return {
    /* add members that will be exposed publicly */
  };
}();

View the addressbook.html file in your browser. The browser should give you a black page, which is not very exciting, but what we have done is created the skeleton for our application. Next, we will start building the application features.

Adding the application features

Our address book application captures, stores, and displays contacts details of our family and friends.

Capturing and storing contacts

Let's develop the functionality to capture and store the contacts. The two pieces of information we want to capture and store is the contact name and phone number. This is defined as a model in our AddressBook module. To do this, open the addressbook.js file and add the following code:

/* add members here */
  var contact = {
  name: ko.observable(),
  phoneNumber: ko.observable()
};

The code defines a contact object with two attributes—name and phoneNumber. The attributes are Knockout observables. We will bind the contact object to our HTML input fields to capture user input. Before we add the HTML fields and the binding construct, we need to expose the contact object publicly so that it can be accessed outside our module, for example, by our HTML binding construct. This is done by adding the contact object to the return statement of our module. Let's add the contact object to the return statement. Here is what the code should be:

return {
  /* add members that will be exposed publicly */
  contact: contact
};

Let's now add the HTML input fields to our view and bind them to our view model. Open addressbook.html and the following code in the body of the HTML; take this opportunity to also change the title of the HTML page to something more appropriate like Knockout: Address Book Example:

<p>Name <input type="text" data-bind="value: AddressBook.contact.name" /></p>

<p>Phone Number <input type="text" data-bind="value: AddressBook.contact.phoneNumber" /></p>

In the preceding code, we have declared two HTML input fields, one for the contact name and the other for the contact phone number. We also added the binding construct by using data-bind. Notice the way we accessed the model. For example, to access the name attribute of the contact, we used the name of our module, AddressBook; followed by the name of our model object, contact; followed by the name of the attribute, name.

The capturing of user input is not complete without a button to indicate that the user has entered a new contact. Add a button to your HTML by inserting the following line after the input text fields:

<p><button data-bind="click: AddressBook.addContact">Add</button></p>

The preceding code will add a button to your view with the Add label. It also adds a click binding. As a result of the click binding, an addContact function will get executed when the user clicks on the Add button. We have not yet defined the addContact method. Let's do this by adding the following code to our view model:

var addContact = function () {
console.log("Adding new contact with name: " + contact.name() +" and phone number: " + contact.phoneNumber());
};

The code displays the values of contact name and phone number from the contact object in the browser console. Notice how we access the value of the name and phoneNumber observables. The addContact method needs to be publicly accessible as it is referenced in our view. Let's do this by adding it to the return statement of our module. Our return statement should now look similar to this:

return {
  /* add members that will be exposed publicly */
  contact: contact,
  addContact: addContact
};

We are missing one very important step before we can run what we have developed so far. That step is to activate Knockout. Add the following line of code to the init function in our module:

var init = function () {
  /* add code to initialize this module */
  ko.applyBindings(AddressBook);
};

Here, the applyBindings function takes view model as the parameter and applies the bindings declared in our view to the model and behavior, defined in our view model. We pass the view model to the applyBindings function by passing our AddressBook module.

Now that our application is capturing the contact details, let's develop the functionality to store the contacts. The contacts will be stored using an array. We cannot use the normal JavaScript array as we will need to bind the array to our view in order to display the contacts. Knockout provides a way to construct an array of observables. To make an array of contacts, add the following code to our AddressModule below the contact:

var contacts = ko.observableArray();

The observableArray function returns an object, which can track the objects it holds. This means that any subscriber will be notified when an object is added or removed from it.

Note

The members of the objects that observableArray hold, do not become observables. This, however, can be achieved through additional code.

Now that we have declared our contacts array, let's add the contact to our contacts array. Modify the addContact function and add the following line of code to push a contact to the contacts array. Your addContact function should look similar to this:

var addContact = function () {
console.log("Adding new contact with name: " + contact.name() +" and phone number: " + contact.phoneNumber());

//add the contact to the contacts array
contacts.push({name: contact.name(), phoneNumber: contact.phoneNumber()});
};

Knockout observableArray provides useful methods to interact with the array. We have used a method push, which insets a new item at the end of the array. We pass a new contact object to the push method by creating an object with name and phone number as attributes. The value of the attributes come from our name and phoneNumber observables in the contact object.

You may have noticed that the input fields for name and phone numbers retain their values after the add button is clicked and the object is added to the contacts array. This is not for user experience as the user has to clear the inputs before a new contact can be added. To clear the input fields, add the following method to your AddressBook module:

var clearContact = function () {
  contact.name(null);
  contact.phoneNumber(null);
};

Call this method from your addContact method after pushing the new contact to the contacts array. The clearContact method clears the values of the name and phoneNumber observable by setting them to null. The two-way data binding takes care of updating the HTML input fields. You do not have to add the clearContact method to the return statement of the module as this a private member, which is not required by any other external module or view.

So far, we have:

  • Developed our application skeleton

  • Created our view with two HTML input text fields for capturing contact name and phone number, and a button to allow user to add a contact

  • Created our module with a model for capturing the user input and storing contacts in an array

  • Added functionality to add the contact to the contacts array and clear the input fields

  • Added declarative binding to our view to bind the HTML input fields to the contact object and the Add button to the addContact function in our view model

  • Activated Knockout by calling the applyBindings function in our init function

Let's run our application and see what happens. Open addressbook.html in a browser. Don't forget to open the console window of the browser. Try adding a contact.

Note

You can open the console window in Chrome by hitting the F12 key and selecting Console in the menu bar.

The application should look similar to this:

Displaying contacts

The next application feature we will add to our address book application is displaying the list of contacts in a table. We will use the HTML table element with foreach binding. Let's get straight into it.

Open the addressbook.html file and add the following code under the input HTML fields:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Phone Number</th>
    </tr>
  </thead>
  <tbody data-bind="foreach: AddressBook.contacts">
    <tr>
      <td data-bind="text: name"></td>
      <td data-bind="text: phoneNumber"></td>
    </tr>
  </tbody>
</table>

In the preceding code, we are using the foreach binding to repeatedly render a table row of contacts. The foreach binding provides a loop construct to display HTML elements based on a template. The HTML markup within the tbody element is used as the template to render each contact.

The data binding declaration in the preceding code refers to the contacts array in our module. We have not yet declared the contacts array to be publicly accessible. Make the contacts array publicly accessible by adding it to the return statement of your module. The return statement of AddressBook module should look similar to this:

return {
  /* add members that will be exposed publicly */
  contact: contact,
  contacts: contacts,
  addContact: addContact
};

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Run the application by opening addressbook.html in a browser. Try adding some contacts. You should now be able to see the newly added contacts displayed in the table. The application should look similar to this:

Adding style to your application with Bootstrap

We have added the application features to our address book application, but the application does not look very visually appealing. Let's make it a bit more attractive by adding Bootstrap to our address book application.

Note

Bootstrap is a popular HTML, CSS, and JavaScript framework for developing web applications. It provides out-of-the-box styles for HTML elements such as labels, buttons, and tables. Find out more about Bootstrap at http://getbootstrap.com/.

Follow these steps to download and set up Bootstrap:

  1. Download Bootstrap from the Bootstrap website.

  2. Create a bootstrap folder under WebContent.

  3. Extract the contents of the download package in the bootstrap folder created in the previous step.

Your folder structure should look similar to this:

You are now ready to use Bootstrap. Include the Bootstrap theme in your application by adding the following line to your HTML inside the head element. Your head element should look similar to this:

<head>
  <meta http-equiv="Content-Type" content="text/html" />
  <title>Knockout : Address Book Example</title>
  <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
  <script type="text/javascript" src="javascript/jquery-2.1.3.min.js"></script>
  <script type="text/javascript" src="javascript/knockout-3.2.0.js"></script>
  <script type="text/javascript" src="javascript/addressbook.js"></script>
</head>

You are free to make your own layout and style choices if you are familiar with Bootstrap. If not, you can follow these steps and make the changes to add the Bootstrap styling to your application:

  1. Wrap the contents of the HTML body in a div element and give it a class, container.

  2. Add a heading using the h1 element just after the body and wrap it in a div element. Give the div element a page-header class like this:

    <div class="page-header"> <h1>My Address Book</h1></div>
  3. Wrap the HTML input fields and the button in a p element. Remove any p elements that the input fields were previously wrapped in.

  4. Add btn and btn-primary classes to the Add button, like this:

    <button class="btn btn-primary" data-bind="click: AddressBook.addContact">Add</button>
  5. Add the table class to the contacts table, like this:

    <table class="table">

After making these modifications, your address book application should look, like this:

You have successfully completed your first Knockout application! Let's look at some useful resources and summarize what we learned.