Contents
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