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

Understanding the module pattern and its use with Knockout


In the previous section, we explored the key features of Knockout. We learned the basics of declarative data binding, automated UI refresh, dependency tracking, and templating. Knockout does a really good job of simplifying web application development by providing these features. However, it does not solve the problem of bringing structure to your JavaScript code.

Unlike an object-oriented programming language such as Java or C#, JavaScript does not enforce any particular structure. This is both a blessing and a curse. Blessing in the sense that you can bring your own rules on how to structure your code. This gives you power and flexibility. It can be a curse if you do not follow any structure as in that case, your code base becomes too large and complex. Giving structure to your JavaScript code becomes more and more important as you write complex JavaScript applications. Structuring your JavaScript will make the code more maintainable and readable. It also helps to make the code more testable.

The concept

An elegant yet simple way of giving structure to your JavaScript code is by using the module pattern. It is important to understand the basic concepts behind the module pattern as we will be using this pattern throughout this book. Let's get started with the basic concept.

Central to the module pattern is the concept of a module. A module is a component that encapsulates everything that is required to accomplish a set of related tasks. This includes data as well as behavior. Here is an example of creating a module using the module pattern in JavaScript:

(function () {
  /* module code */
}) ( );

Let's deconstruct and explore what the preceding code does. Since JavaScript does not provide a construct for creating modules or classes, we use the next best thing—the anonymous function construct. The preceding code constructs and executes an anonymous function. The module code inside this function maintains privacy from the outside world. This is because creating a function creates a new scope. The module code also maintains its state throughout the life cycle of the module. Notice the parenthesis ( ) at the end of our function. These parenthesis execute our anonymous function straight after creation and creates our module.

Note

By convention, the modules are named with uppercase first letter.

We need a way to namespace our newly created module. This will allow us to access any public attributes that the module might expose:

var Module = (function () {
  /* module code */
})( );

In the module we defined here, the scope of any attributes or function is confined to the module. You cannot access an attribute that is declared within the module. This is exactly what we want to do—encapsulate everything related to a set of tasks.

Public and private members

If everything is now encapsulated, how does the outside world interact with our module? The answer is a return object with references to attributes and functions that we want to expose to the outside world. With the public and private members defined, the module will look similar to this:

var Module = (function () {
  /* private attribute */
  var privateAttribute;

  /* private function */
  var privateFunction = function () {};

  /* public attribute */
  var publicAttribute;

  /* public function */
  var publicFunction = function () {};

  /* return object with reference to public attributes and functions */
  return {
    publicAttribute: publicAttribute,
    publicFunction: publicFunction
  };
})();

The scope of the private members, prefixed with the word private, is confined to the module. The public members, prefixed with the word public, are exposed to the outside world through the return object. The return object simply references the public members. We can now access the public members as follows:

Module.publicAttribute = 'foo';
Module.publicFunction();

Initializing the module

One final element I want to add to my module is a function that initializes the module. Some people like to call it a constructor. Strictly speaking, a constructor is a function that creates an object. It can, however, contain initialization logic. This is not what our function will do. Our function will only initialize the module, hence I won't be calling it a constructor. You can choose any name for your initialization function. I like to call it init. Let's add the init function to our module:

var Module = (function () {
  /* private attribute */
  var privateAttribute;
  /* private function */
  var privateFunction = function () {};

  /* public attribute */
  var publicAttribute;

  /* public function */
  var publicFunction = function () {};

  var init = function() {
    /* Module initialization logic*/
  };

  /* fire the init function */
  init();

  /* return object with reference to public attributes and functions */
  return {
    publicAttribute: publicAttribute,
    publicFunction: publicFunction
  };
})();

In the preceding example, we can see the init function being declared. The scope of this function is private as it is not exposed by the return object. Declaring the function does not mean that our function will execute when the module is created. We execute the function by calling it after declaration:

/* execute the init function */
init();

On most occasions, we want to execute our init function after the HTML is fully loaded by the browser and the DOM is ready. This is where jQuery comes handy. We can use a feature provided by jQuery to execute the init function once the HTML is fully loaded and the DOM is ready. This is done by replacing the call init(); with:

/* execute the init function once the DOM is ready */
jQuery(init);

Passing any function as an argument to the jQuery function executes it once the DOM is ready. In the preceding code, we pass the init function as an argument to the jQuery function.

Tip

The dollar sign, $, is a short hand for jQuery. jQuery() is the same as $().

Using the module with view model

Now that we have learned the basic concepts behind the module pattern, let's declare the contact view model we used earlier as a module:

var ContactViewModel = (function () {
  var contact = {
    id: ko.observable(1),
    name: ko.observable('John'),
    phoneNumber: ko.observable(00001111)
  };

  Var retrieveContact = function (){
    /* logic to retrieve contact form server side data repository */
  };

  Var updateContact = function (newPhoneNumber){
    /* logic to update the contact with new phone number */
  };

  var init = function() {
    /* Module initialization logic*/
  };

  /* execute the init function once the DOM is ready */
  $(init);

  return {
    contact: contact,
    updateContact: updateContact
  };
})();

Our preceding module is referenced by ContactViewModel. It has a contact model and functions to retrieve and update the contact. It also has an initialization function, which will be executed once the DOM is ready. The module exposes the contact model and the updateContact function as public members to the outside world. The retrieve contact function remains private to the module.