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.
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.
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.
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:
Create the
AddressBook
folder. This is the main folder that houses our address book application.Add a
WebContent
folder under theAddressBook
folder. This folder holds the content that gets published to the web.Add a
javascript
folder under theWebContent
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:
Add the Knockout library that you downloaded to the
javascript
folder.Add the JQuery library that you downloaded to the
javascript
folder.Create the
addressbook.js
file under thejavascript
folder.Create the
addressbook.html
file under theWebContent
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.
Our address book application captures, stores, and displays contacts details of our family and friends.
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 theaddContact
function in our view modelActivated Knockout by calling the
applyBindings
function in ourinit
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:
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:
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:
Download Bootstrap from the Bootstrap website.
Create a
bootstrap
folder underWebContent
.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:
Wrap the contents of the HTML body in a
div
element and give it a class,container
.Add a heading using the
h1
element just after the body and wrap it in adiv
element. Give thediv
element apage-header
class like this:<div class="page-header"> <h1>My Address Book</h1></div>
Wrap the HTML input fields and the button in a
p
element. Remove anyp
elements that the input fields were previously wrapped in.Add
btn
andbtn-primary
classes to theAdd
button, like this:<button class="btn btn-primary" data-bind="click: AddressBook.addContact">Add</button>
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.