Knockout.js

 

Overview

* Open source JavaScript library.
* Light weight, no other dependencies.
* Implements MVVM pattern (Model-View-ViewModel)
– Model: binds view model to view, e.g.:

        ko.applyBindings(viewModel);

– View: contains HTML/CSS elements for data to bind to, e.g.

    <h1>Hello <span data-bind="text: name"></span>!</h1>

– View Model: contains data to be bound to the view, e.g.

        function ViewModel() {
            this.name = 'John Doe';
        };
        var vm = new ViewModel();

* Framework can be extended using Knockout plugins.

Data Bindings

Data Binding Syntax

* Data binding is achieved by using HTML attribute: data-bind

    <h1>Hello <span data-bind="text: name"></span>!</h1>

* Data binding can also be done with:

<!-- ko -->
<!-- /ko -->

e.g.

    <!-- ko foreach: books --> 
        <li data-bind="text: $data"></li> 
    <!-- /ko -->

* Can bind almost any:
– HTML attribute
– CSS class
– CSS style

Binding Multiple View Models on a Single Page

* You can bind different view models to different elements on a single page.
* Syntax:

    <div id="greeting1">
        <h1 data-bind="text: greetings()"></h1>
    </div>
    <div id="greeting2">
        <h1 data-bind="text: greetings()"></h1>
    </div>
 
    <script>
        var vm1 = new Greeting('John');
        ko.applyBindings(vm1, document.getElementById('greeting1'));
 
        var vm2 = new Greeting('Jane');
        ko.applyBindings(vm2, document.getElementById('greeting2'));
    </script>

Text (text:) Binding

    <h1>Hello <span data-bind="text: name"></span>!</h1>

HTML (html:) Binding

    <h1>Hello <span data-bind="html: getName()"></span> with HTML binding!</h1>

CSS (css:) and Style (style:) Binding

    <p data-bind="
        style: { marginBottom: 0, paddingBottom: '1em' },
        css: 'myClass'">
        Hello css binding!.
    </p>
 
    <div class="myHeader"
         data-bind="css: {myHeaderOne: $data.isHeaderOne, myHeaderTwo: $data.isHeaderTwo}">

Attribute (attr:) Binding

    <p data-bind="attr: { id: 'myId' }">
        Hello attribute binding.
    </p>

Conditional (if: and ifnot:) Binding

* if binding:

    <div id="summary" class="section panel panel-primary"
         data-bind="if: model.displaySummary">
    </div>

* ifnot binding:

    <div id="editor" class="section panel panel-primary"
         data-bind="ifnot: model.displaySummary">
    </div>

* Tertiary expression

<button type="submit" data-bind="text: (!hasName()) ? 'Create' : 'Update'">

foreach: Binding

* Works with multiple objects and repeats the HTML in the binding.
* Example:

    <ul>
        <!-- ko foreach: friends -->
        <li data-bind="text: $data"></li>
        <!-- /ko-->
    </ul>

* foreach binding callback events:
– afterRender
– adterAdd
– beforeRemvoe
– beforeMove
– afterMove

with: Binding

* Similar to foreach but:
– works with a single object with multiple properties
* Example:

    <div id="address" data-bind="with: address">
        <p data-bind="text: street"></p>
        <p data-bind="text: zip"></p>
        <p data-bind="text: state"></p>
    </div>

template: Binding

* Use template binding to reuse templates.

<div data-bind="template: {name: 'greeting-template2', foreach: greetings}">
<script type="text/html" id="greeting-template2">
    <span data-bind="text: greet"></span> 
    <span data-bind="text: solute"></span> 
    <span data-bind="text: $parent.name"></span><br/>
</script>

Form Data Binding

* value : used with input, select and textarea
– observables updated when field value changes
* textInput : used with input and textarea
– observables updated when field loses focus
* checked : used with checkboxes and radio buttons
* options : used with select
* selectedOptions : used with the multiple select list
* enabled and disable : enable/disable whole form

Event Data Binding

* submit
* click
* hasFocus
* event
* For example:

    <textarea data-bind="value: myText, event: { mouseover: clearText() }"></textarea>

Form Processing

Form Validation

* Use jQuery validate plugin

Install-Package jQuery.Validation

Form Posting with AJAX

* Form data can be posted via Ajax using either JavaScript or JSON formats:

    data: ko.toJS(self.person),
    data: ko.toJSON(self.person),

Variables

Built-in Variables

$root
$parent
$parents
$data
$index

Observables Variables

* Used to handle dynamically changing properties
* Don’t use for static non-changing values as observables have performance costs

Define Observables

// observable
var myobs1 = ko.observable();
 
// observable array
var myobs2 = ko.observableArray([]);
 
// computed observable
var myobs3 = ko.computed(function() {
  return //computed value here
});
 
// pureComputed observables (for version 3.2 and later)
// lazy instantiation to improve performance
var myobs4 = ko.pureComputed(function() {
  return //computed value here
});

Access Observables

* In JavaScript, Observables must be accessed like a function, i.e. with ().

myobs1('Hello');
alert(myobs1());
 
myobs2.push('Hello');
alert(myobs2());

* Observables can also be access by name in data-bind attributes (Knockout converts it to function call).

        <h1>Hello <span data-bind="text: computedFullName"></span>!</h1>

Extend Observables

* Obersables can be extended, e.g.:

        ko.extenders.maxCharacters = function (target, max) {
            var result = ko.computed({
                read: target,
                write: function (newValue) {
                    alert(newValue);
                    var current = target();
                    if (newValue.length <= max) {
                        target(newValue);
                    } else {
                        target(current);
                        target.notifySubscribers(current);
                    };
                }
            }).extend({ notify: 'always' });
 
            return result;
        };

Add Custom Functions to Observables

* You can also add custom functions to observables, e.g.:

        ko.observableArray.fn.booksOwned = function (property, value) {
            return ko.computed(function () {
                var allItems = this();
                var machingItems = [];
 
                for (var i = 0; i < allItems.length; i++) {
                    var current = allItems[i];
                    if (ko.unwrap(current[property]) === value) {
                        machingItems.push(current);
                    };
                };
 
                return machingItems;
            }, this);
        };

Limit Notification Rate for Observables

* You can also limit how often observable notifies subscribers:

myObservable.extend({ rateLimit: 1000 });
 
myObservable.extend( {
    rateLimit: {
	    timeout: 1000,
	    method: "notifyWhenChangesStop"
    }
});

Subscribe to Observable Events

* By implementing the subscribe function.

    self.myText.subscribe(function () {
        self.msg('myText changed to: ' + self.myText());
    });

Knowout Mapping Plugin

* Used to automatically map a standard JavaScript object or JSON data to a new objects with each property being an observable object.
* Plugin file: knockout.mapping.js
* Install plugin from NuGet:
Install-Package Knockout.Mapping
* Map from JavaScript object
– use mapping to ignore certain properties

    <div data-bind="with: book1">
        <h1 data-bind="text: title"></h1>
        <h2 data-bind="text: author"></h2>
        <h2 data-bind="text: isbn"></h2>
    </div>
    <script>
        function ViewModel() {
            var self = this;
 
            var mapping = {
                'observe': ['title', 'author'],
                'ignore' : ['isbn']
            };
 
            self.book1 = ko.mapping.fromJS(book, mapping);
        };
 
        var book = {
            title: 'Book One',
            author: 'John Doe',
            isbn: '12345'
        };
 
        var vm = new ViewModel();
        ko.applyBindings(vm);
 
    </script>

Examples

* See here for examples.

References

* Knockout.js by Jamie Munro Published by O’Reilly Media, Inc., 2014
* Knockout home page

This entry was posted in JavaScript, Knockout and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

This site uses Akismet to reduce spam. Learn how your comment data is processed.