Knockout is javascript library which is used on frontend in Magento 2. It implements Model-View-View Model (MVVM) design pattern. You can find Knockout in Magento 2 on almost every page. The place where it’s most present is the checkout page. This is the most complicated implementation in Magento 2.
The goal of this post is to explain how to write KO Model-View and View which is valid to use in Magento 2.
We will demonstrate how to implement very simple logic and try to explain the base concepts.
If you’re not familiar with Knockout library I suggest that you read documentation on url: http://knockoutjs.com/documentation/introduction.html.
In our example, all files are located in “Inchoo_Js” module. For this example we created our View-Model in file “koexample.js”, located at: app/code/Inchoo/Js/view/frontend/web/js/koexample.js.
Example of our View-Model is below:
define(['uiComponent'], function(Component) {
return Component.extend({
initialize: function () {
this._super();
this.sayHello = "Hello this is content populated with KO!";
}
});
});
Our View-Model has as dependency ‘uiComponent’ (Magento_Ui/js/lib/core/collection.js). UiComponent inherits class and methods from “uiElement” (Magento_Ui/js/lib/core/element/element.js) and over last class our View-Model has implementation of Knockout logic.
If you open “Magento_Ui/js/lib/core/element/element.js” you will notice ko object as dependency in define function from requireJS:
define(['ko', 'underscore', 'mageUtils', 'uiRegistry', 'uiEvents', 'uiClass', './links', '../storage'],
function (ko, _, utils, registry, Events, Class, links) {
'use strict';
....
View-Model should populate some html content or View. For this purpose we created very simple View in phtml file:
<div data-bind="scope: 'koexample'">
<!-- ko template: getTemplate() --><!-- /ko -->
</div>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"koexample": {
"component": "Inchoo_Js/js/koexample",
"template" : "Inchoo_Js/example"
}
}
}
}
}
</script>
In our example we used Knockout template file example.html, which contains next content (template file is defined in code above “template” : “Inchoo_Js/example”). Template file is dynamically loaded by javascript.
<p>I am template located on: app/code/Inchoo/Js/view/frontend/web/template/example.html and dynamically loaded. This is my message to you:</p>
<p data-bind="text: sayhello"></p>
After activating Knockout your view should display:
<p>I am template located on: app/code/Inchoo/Js/view/frontend/web/template/example.html, dynamically loaded. This is my message to you:</p>
<p data-bind="text: sayhello">Hello this is content populated with KO!</p>
One of the big key benefits of Knockout is that KO updates your content automatically when View-Model is changed. In order to make automatically update content you should in your View-Model class declare property as observable.
We will demonstrate observable logic with “this.time” property in our View-Model. We will periodically update property and View should be updated. The best explanation is on the working example. Let’s go.
define(['uiComponent'], function(Component) {
return Component.extend({
initialize: function () {
this._super();
this.time = Date();
//time is defined as observable
this.observe(['time']);
//periodically updater every second
setInterval(this.flush.bind(this), 1000);
},
flush: function(){
this.time(Date());
}
});
});
In “initilalize” method we created property “time” and declared as observable with method “this.observe([‘time’])“.
This “observe” method is from class “Magento_Ui/js/lib/core/element/element”. If you want to examine the whole logic, open this file and find method “observe”.
With javascript function “setInterval” we periodically update property “time” with new value. It means that KO should automaticaly update View with new value.
One more thing, you should modify your View (ko template file) and it should look like seen below:
<p>I am example3.HTML template, dynamically loaded. This is my message to you:</p>
<p data-bind="text: time"></p>
When you activated Knockout, html/content should be updated every second. Html should look like this:
<div data-bind="scope: 'koexample'">
<!-- ko template: getTemplate() --><p>I am example3.HTML template, dynamically loaded. This is my message to you:</p>
<p data-bind="text: time">Mon Mar 07 2016 12:58:30 GMT+0100 (CET)</p><!-- /ko -->
</div>
Time is updated every second by Knockout using observable.
I hope that you understood this simple example and that it will be helpful in your development.
In case you feel you need some extra help, we can offer you a detailed custom report based on our technical audit – feel free to get in touch and see what we can do for you!