How to use Knockout in Magento 2

knockout-01

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.


About Domagoj Potkoc

Backend Developer

Domagoj is Magento Certified Developer who enjoys playing tennis after long hours in front of computer screen.

Read more posts by Domagoj / Visit Domagoj's profile

11 comments

  1. hopefully someone is still watching this, but can you explain how the flush method is being called in the initialize part of the code. To be more precise which object is calling the bind method?

  2. Please update your tutorial to clarify this statement: “For this purpose we created very simple View in phtml file” — what is the filename and path for this file?

  3. This is a really terrible tutorial.. The English isn’t great, which I can forgive, but you’re missing information like what to name/where to save files, file paths appear to be incorrect.

    I would be surprised if anyone was able to get any help from this at all

  4. @michal create a folder template inside web and put your html files , not in regular templates folder. Worked for me

  5. Thats just enough information to be frustrating. Would you mind just zipping the example you wrote and uploading it so we can download it and find all the correct paths and filenames? Thanks

  6. Hi, thanks for the tutorial!

    I have a question to this, in which file should I paste the together with the KO getTemplate?

    I have the Viewmodel at
    app/code/Vendor/Module/view/frontend/web/js/viewmodel.js

    I have the html template at:
    app/code/Vendor/Module/view/frontend/web/template/template.html with contents “data-bind=”text: sayhello”

    In which file should I place the script type=text/x-magento-init part?

  7. sayHello is case sensitive, To make this example work correct the sayhello in the example.html.

  8. Do you know maybe, why magento knockout component couldn’t fetch template ? You can see below that I have all declared as you wroted in the article? I will be very thankful when you will give me any hint 🙂 Thanks in advance!

    <div data-bind="scope: 'jsmodulename'">
            <!-- ko template: getTemplate() --><!-- /ko -->
        </div>
    
        <script type="text/x-magento-init">
            {
                "*": {
                    "Magento_Ui/js/core/app": {
                        "components": {
                            "jsmodulename": {
                                "component": "Vendor_ModuleName/js/view/componentfilename",
                                "template" : "Vendor_ModuleName/templatefilename"
                            }
                        }
                    }
                }
            }
        </script>
    1. @Michal
      Please check path to your template file.
      In my example my file is located on:
      app/code/Inchoo/Js/view/frontend/web/template/example.html

      Also Extension of file should be html.

    2. Yes paths are checked couple of times :). I am working on admin side, so template is placed in app/code/Vendor/ModuleName/view/adminhtml/web/template/templatename.html. I think that I have this issue, because of the fact that I am trying to initialize knockout app after loading via ajax phtml content in which above code is placed. After phmtl content is loaded into admin tab via ajax I have to trigger ‘contentUpdated’ event to let magento engine know that it has to parse

      <script type="text/x-magento-init">

      again. Maybe because of that, fetching template method is not working properly. Did you do in the past something similar?

  9. Hello, can you please create example, how to create similar pop up like sometimes checkout show, using ko templates for login and registration

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.