Object JavaScript – Dynamic UI Using Observables with MVVM Using Knockout.js

knockoutIn our previous posts, you learned how to build modules. In the next series of posts, you will learn how you can connect up modules to the user interface. You will learn, step by step how to use observables for your user interface to dynamically update itself.

Knockout.js makes it easier to create rich, responsive UIs with JavaScript. Any time you have sections of UI that update dynamically (e.g., changing depending on the user’s actions or when an external data source changes), KO can help you implement it more simply and maintainable.

Knockout helps you build rich client-side interactivity by using an MVVM-like (Model, View, and ViewModel) pattern. It does this by helping you separate the UI behavior and the data structures. To do this, you will use declarative bindings with observable data.

Knockout is free, open source, and available for your projects using the MIT License.

Knockout helps you:

  • Synchronize JSON models with HTML elements using Observable Properties.
  • Synchronize arrays, using Observable Arrays.
  • Provide calculated properties using Computed Properties.

Key Concepts

Knockout.js is built around several key concepts:

  • View, ViewModel. The view is the HTML document that displays the user interface. The viewmodel is a JavaScript object that represents all the data and operations in the view.
    • Declarative bindings. You associate DOM elements with your data model using a concise, readable syntax.
    • Automatic UI refresh. When your data model’s state changes, your UI updates automatically – using observables.
    • Dependency tracking. Implicitly set up chains of relationships between model data, to transform and combine it.
    • Templating. Quickly generate sophisticated, nested UIs as a function of your model data.

    About Observables

    Observables are a pattern used in software development where an object maintains a list of its dependents, called observers, and notifies them automatically of any state changes. When an observable value in the view model changes, so does the view, and vice-versa.

    Computed observables compute their values based on the values of other observables.

    Knockout tracks dependencies, so that whenever an observable’s value changes, any computed observables that use that observable are run automatically to compute their new values.

    Knockout Browser Support

    Knockout supports has good support among browsers. IE 6 and greater, Firefox 2 and above, and the latest versions in Chrome, Opera, and Safari. The Knockout team regularly checks for support in Opera Mini and Android. You can also run the test cases yourself.

    Download the source code, then open /spec/runner.html on the browser, which will test more than 100 behavioral specifications and produce a report of any problems.

    Getting Knockout.js

    There are a variety of ways you can get Knockout.js for your application:

    PM> Install-Package knockoutjs 

    Getting Started with Knockout.js

    You reference knockout.js library using a <script> tag somewhere on your HTML pages. For example:

    <script type='text/javascript' src='knockout-2.2.1.js'></script>
    

    Of course, for Web application, you can substitute the a CDN instead of the filename.

    (Note, you can also identify Knockout as a dependency in your modules using require.js. For more information, see Knockout’s documentation on Asynchronous Module Definition (AMD) With RequireJs.)

    You can find out the latest stable production version in the Knockout online documentation.

    Your Code

    Next, there are three steps in getting started with Knockout.

    First you need to have something in your view that your user interface will be binding to. This is where you declare your binding data. In the case, the value property of the input element will be set to the firstName property in our view model.

    <p>First name: <strong data-bind="text: firstName"></strong></p>

    Next you need to have the firstName property defined as an observable in your viewmodel.

    var myViewModel = {
        firstName: ko.observable('John');
    }

    And then you need to apply the bindings between the viewmodel and the view. This is how you take the data in your viewmodel and bind it to the elements on the page.

    ko.applyBindings(myViewModel);

    What is MVVM

    MVVM is a way to separate and organize your data, and then to display it using data binding. MVVM consists of:

    • The Model  contains the data points that the application requires. These classes (sometimes known as domain objects) may be collection classes or single entity classes. The main responsibility of a Model is to describe the data required by the client.
    • The View is the friendly presentation of information to the user. A View may include themes, styles, controls, bindings, events, and other interactions on the screen. The View’s responsibility is to keep all presentation in a single place, unencumbered by logic and other heavier code. Often the View will have controls that will map to one or more Model’s data points.
    • The ViewModel is the glue between the View and the Model(s). The ViewModel is also known as the “View’s Model” because it exposes public properties intended for the View. Often the ViewModel aggregates one or more Models and exposes them to the View as public properties.

    A ViewModel is the glue between the View and the Model.

    MVVM is a pattern and is language and platform independent. It is an important pattern used in Silverlight, Windows Phone, Windows 8, WPF applications. And there are plenty of ways to support MVVM.

    In the case for this article, we’ll be using Knockout and our own models in JavaScript.

    The Model

    This is the data. It is a JavaScript object that contains the data. In this example, we have the model described in a JavaScript variable named data.

    image

    The View

    This is the Web page, the HTML. It is the user-friendly presentation of information. In this case, we have a some span and div objects that we can bind to the data.

    image

    The ViewModel

    Behavior and data for the view. It contains properties, methods and the model.

    image

    In this case, the viewmodel contains a set of properties that are Knockout Observable.

    Knockout observable

    A Knockout Observables are special JavaScript objects that can notify subscribers about changes, and can automatically detect dependencies.

    When you use observables, the objects themselves are now capable of detecting changes, and when it does, it will update the view automatically.

    ko.observable objects are actually functions.

    • To read the observable’s current value, just call the observable with no parameters. In this example, myViewModel.personName() will return 'Bob', and myViewModel.personAge() will return 123.

    • To write a new value to the observable, call the observable and pass the new value as a parameter. For example, calling myViewModel.personName('Mary') will change the name value to 'Mary'.

    • To write values to multiple observable properties on a model object, you can use chaining syntax. For example, myViewModel.personName('Mary').personAge(50) will change the name value to 'Mary' and the age value to 50.

    Computed Observable

    computed observables are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change.

    For example, you might have a person object with a first name and last name. You can then calculate the full name in the viewmodel object.

    function AppViewModel() {
        this.firstName = ko.observable('Bob');
        this.lastName = ko.observable('Smith');
        // calculated observable
        this.fullName = ko.computed(function() {
          return this.firstName() + " " + this.lastName();
        }, this);
    }

    Whenever firstName or lastName changes (your evaluator function will be called once each time any of its dependencies change, and whatever value you return will be passed on to the observers such as UI elements or other computed observables.

    A computed observable will be re-evaluated whenever one of the observables that it accessed in its last evaluation changes.

    Knockout Two-Way Binding Demo

    Here’s the demo code that shows these features.


    <!DOCTYPE html>
    <html>
    <head>
    <title>MVVM 1</title>
    </head>
    <body>
    <!– the view –>
    <p>First name: <strong data-bind="text: firstName"></strong></p>
    <p>Last name: <strong data-bind="text: lastName"></strong></p>
    <p>Age: <strong data-bind="text: age"></strong></p>
    <p>Full name: <strong data-bind="text: fullName"></strong></p>
    <p>Edit first name : <input data-bind="value: firstName" /></p>
    <p>Edit last name: <input data-bind="value: lastName" /></p>
    <p>Edit age: <input data-bind="value: age" /></p>
    <script src="Scripts/knockout-2.2.1.debug.js"></script>
    <script>
    //The model defines the data for the object
    var dataModel = {
    firstName: "Hello",
    lastName: "There",
    age: 23
    }
    // viewmodel defines behavior
    function viewModel() {
    var self = this;
    self.firstName = ko.observable(dataModel.firstName);
    self.lastName = ko.observable(dataModel.lastName);
    self.age = ko.observable(dataModel.age);
    // add computed field
    self.fullName = ko.computed(function () {
    return self.firstName() + " " + self.lastName();
    });
    }
    // Activates knockout.js and binds the viewModel to the view
    ko.applyBindings(new viewModel());
    </script>
    </body>
    </html>

    References

    Get started with knockout.js quickly, learning to build single-page applications, custom bindings and more with these interactive tutorials.

    Channel 9 Video: Knockout JS: Helping you build dynamic JavaScript UIs with MVVM and ASP.NET

    10 Things to Know About KnockoutJS on Day One