Knockout JS
Part 1

Table of contents

  1. Overview
  2. Observables
  3. Computed Observables
  4. Bindings
  5. Custom bindings
  6. Components
  7. Pros and Cons

1. Overview

Knockout JS is a JavaScript library that is used on the frontend in Magento 2. It executes Model-View-View Model (MVVM) design pattern. To understand the term “Knockout JS,” let’s first have a quick view of MVVM.

MVVM Design Pattern

MVVM consists of three components:

  • Model: contains all data of the application
  • View: represents the user interface (UI)
  • View Model: is the intermediate layer between Model and View. It manages and handles the application logic. A ViewModel can be used for multiple views.

For example, Model contains a list of information such as name, number, address, etc. View Model updates the data between Model and View and handles the format of the number, name, etc.

Knockout JS

Knockout JS helps Web applications work smoothly and flexibly according to user actions. Here are its outstanding features:
  • Elegant dependency tracking - automatically update related UI components when data changes (Observables)
  • Declarative bindings - creates constraints of UI components with Model. Knockout JS processes data between View and Model using HTML tags to mark data components.
  • Trivially extensible - easily reuse logic or similar HTML fragments by creating a custom binding, templates, components.

Installation and Initialization

Installation

Download the JS file https://knockoutjs .com/downloads/index.html ,
or use CDN
then declare the JS file in HTM. <script type='text/javascript' src='knockout-3.5.1.js'></script>

Initialization

Example

His name is
He is years old

Note:To enable Knockout JS with limited HTML area, add the second parameter which is an HTML element in the applyBinding function: ko.applyBindings (myViewModel, document.getElementById ('# element'));

2. Observables

First, let's take a look at the Observer Design Pattern in Javascript to get an idea of ​​Observables.
  • In the Observer Pattern, a Subject manages a list of objects that depend on it (Observer), automatically notifying them when there is any change.
  • The dependency of Observers on a Subject depends on two actions of “subscribe()” and “unsubscribe(),” corresponding to assigning or unassigning the Observer to a Subject.
  • The “notify ()” is called when a value is changed. For example, when an input is changed, JavaScript will capture the event using the addEventListener function. The Subject will run around to update new data for all its Observers.

Learn more about this pattern here.
In Knockout JS, the Subject of the Observer Pattern corresponds to ViewModel, while the Observables are properties of ViewModel - the component determines which part of the UI will be automatically updated when changes are made to ViewModel.
Declaration
this.property = ko.observable('value');
Back to the example above:
// Initialize the ViewModel
var myViewModel = {
 personName: 'Bob',
 personAge: 35
};

The “personName” and “personAge” still have the default values, now we will apply Observable to these 2 properties:
var myViewModel = {
 personName: ko.observable('Bob'),
 personAge: ko.observable(35)
};

Example

Name:

Age:

His name is
He is years old

Note: ko.observable is a getter / setter function. Therefore, the way of calling and passing the value is the same as calling the function.

Subscribe

Used when you want to treat an Observable when its data changes, for example:
To get a new value of Observable:
To get the old value, the event will be replaced with "beforeChange":

Read and write the value of Observable

Read: call an Observable without the same parameter:
Write: call the Observable with the parameter is the value you want to set: Write multiple Observables at the same time:

Example

His name is

He is years old

Observable Arrays

Similar to arrays in native JavaScript, but Observable Arrays can also track each child element of the array. They are very useful when you want to display or change several UI elements in a list.
Declaration:
Initialization:
Read a child element of an Observable array:
Processing functions of Observable arrays are similar to the array processing functions of native JavaScript, such as push, pop, splice, etc.
Example
Add new name:

Names data:

3. Computed observables

The Computed Observable is a function that consists of one or more Observables, like a group of many Observables, that can handle the logic in its function.

It automatically updates the value when an Observable inside it changes.
Example

The name is

4. Bindings

The 'data-bind' syntax makes the connection between the UI and ViewModel by marking the position of the Observable on the HTML tag.

Binding syntax

  • One Binding syntax contains two components: binding name, and value. For example: <span data-bind="text: whatDay"></span>
  • Bindings are separated by commas. <input data-bind="value: someValue, valueUpdate: 'afterkeydown'"/>
  • Binding name is the default binding of KO, such as value, text, enable,etc. You can also customize a binding (part 5).
  • Binding value can be a certain value, an Observable, or an expression. The item is <span data-bind="text: price() > 50 ? `expensive` : `cheap`"></span>.

Controlling text and appearance

The "visible" binding <span data-bind="visible: isShow">Visible</span> The "hidden" binding <span data-bind="hidden: !isShow()">Hidden</span> The "text" binding Today is : <span data-bind="text: whatDay"></span> The "html" binding <div data-bind="html: details"></div> The "class" bindings <div data-bind="class: profitStatus"></div> The "css" bindings
<div data-bind="css: { profitWarning: currentProfit() < 0, majorHighlight: isSevere }"></div> The "style" binding <div data-bind="style: { color: currentProfit() < 0 ? 'red' : 'black' }"></div> The "attr" binding <a data-bind="attr: { href: url, title: details }"> Report </a>
Visible
Hidden

Status class
Status css
Status style
Report

Note: If attr or css style is not an ordinary format, or has characters, eg data-name, or font-weight:

<div data-bind="attr: { 'data-name': someValue }">...</div> <div data-bind="style: { fontWeight: someValue }"></div>

Interactive Bindings

The "click" binding <button data-bind="click: handleClick">Click</button> The "event" binding <span data-bind="event: { mouseover: handleMouseover, mouseout: handleMouseout }">Mouse event</span> The "submit" binding <form data-bind="submit: handleSubmit"> ... form contents go here ... <button type="submit">Submit</button> </form> The "enable" and "disable" binding <input type='checkbox' data-bind="enable: isEnable"/> is enable The "value" bindings <input data-bind="value: username" /> The "checked" binding <p>Send me spam: <input type="checkbox" data-bind="checked: isChecked" /></p>
Example

Mouse event
... form contents go here ...
is enable

Send me spam:

Control Flow Bindings

Process Observables in loops, with conditions outside the View.

The "foreach" binding
Works with Observable array

Note: To use “foreach” binding without assigning to HTML element, use it as HTML comment as follows:

<!-- ko foreach: myItems --> <li>Item <span data-bind="text: $data"></span></li> <!-- /ko -->

First name Last name
The "if" and "ifnot" binding
Processes the condition of Observables in the UI.

Note: To use "if", "ifnot" binding you don't need to assign it to HTML element:

<!-- ko if: isDisplayMessage --> <div>Here is a message.</div> <!-- /ko -->

Here is a message.
Here is a Name.

Binding context

Special objects of Knockout JS used to refer to elements in arrays. Here are types of binding context:
$parent
Refers to a parent element on par with the original array.
$parents
Refers to all parent Observables.
$parents[0] // refers to level 1 $parents
$parents[1] // refers to level 2 $parents

$data
Refers to the current element in the loop.
$index Is an index of the element in the array. It is also an Observable, which is updated when the element changes.
  • . The value is

Rendering templates

Allows declaring a template and supports reuse.

Other options in Template:
  • name — an ID to identify the template
  • data — an object to transfer data into the template
  • if — determines whether the template will render or not.
  • foreach — used similar to binding foreach.
  • as — declares the element's representation in the loop
  • afterRender, afterAdd, or beforeRemove — handle the corresponding event after the template renders, after adding or removing elements when working with arrays.

5. Custom bindings

KnockoutJS supports creating a Custom binding name, like value, text, etc.
Declaration:
Meaning of the parameters:
  • element — The DOM element of the tag is declared with a binding.
  • valueAccessor — The current value of the Observable, called as an observable.
  • allBindings — is a JavaScript object used to get the value of other bindings, using: allBindings.get ('name')
  • viewModel — like using $ data in an array.
  • bindingContext — allows reference to $data, $parent, $parents, and $root contexts when working with arrays.
Example
You have selected the option

6. Components

Components in Knockout JS, representing a ViewModel, can be combined with a template to create a widget. It is very useful to use Component to replace the same HTML fragments and reuse.

Component binding without parameters

Component binding passing parameters

Note: Component can be declared in HTML as a HTML tag: In addition, ViewModel or Template can be declared from the file:

7. Pros and Cons

Pros

  • It brings a lightweight library that supports Data binding, which automatically updates the UI.
  • Three classes (including View, Model, ViewModel) are independent of each other, so it's easy to test them.
  • Full documentation.

Cons

  • There is no organization of source code, no division according to a modular structure, which makes it difficult to manage when extending the application.
  • In compare with Javascript framework, when building a SPA application, using Knockout JS is unreasonable because it still has to handle many issues such as Routing, Data storage, etc. Using JS frameworks like Angular / ReactJS / VueJS is a better choice.
  • Regarding performance, it is inferior in data rendering ability compared to other frameworks:

    https://chrisharrington.github.io/demos/performance/