Magento 2 : Use Knockout and UI Component

I am gonna try to give you some mere example on how we can use it.

First of all, I would recommande using the extension on chrome : Knockoutjs context debugger .

This extension allows to inspect knockout context & data for the selected dom node, and save so much time when you are debuging

Let’s start !

Imagine that we have to put a simple button which let appears a discount code for our customer on the product page.
First of all, we have to declare our template in our catalog_product_view.xml

<code lang="xml">
<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="product.info.stock.sku">
            <block class="Magento\Framework\View\Element\Template" name="training" template="Menincode_Training::catalog/product/view/training.phtml"/>
        </referenceContainer>
    </body>
</page>
</code>

Once our template declared in the layout, we can create our phtml file

<?php /** @var Magento\Framework\View\Element\Template $block */ ?>
<div id="training" data-bind="scope: 'myCustomComponent'">
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

<script type="text/x-magento-init">
        {
            "#training": {
                "Magento_Ui/js/core/app" : {
                    "components": {
                       "myCustomComponent" :{
                           "component" :"Menincode_Training/js/training",
                           "template" :"Menincode_Training/training",
                           "catch_phrase" : "Find out your free Discount Code",
                           "another_text" : "I am another text !!!",
                           "discount_code" : "DISCOUNT50"
                       }
                    }
                }
            }
        }
</script>

Note here, that the

data-bind="scope: 'myCustomComponent'"

is important. It allows Magento 2 to apply our myCustomComponent  view model to this part of DOM.

You can notice this line

<!-- ko template: getTemplate() --><!-- /ko --> 

It will call our template declared in our component config: Menincode_Training/training
The path is gonna be Menincode/Training/view/frontend/web/template/training.html

We can also fully declare our configuration through XML

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="product.info.stock.sku">
            <block class="Magento\Framework\View\Element\Template" name="training" template="Menincode_Training::catalog/product/view/training.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="myCustomComponent" xsi:type="array">
                                <item name="component" xsi:type="string">Menincode_Training/js/training</item>
                                <item name="template" xsi:type="string">Menincode_Training/training</item>
                                <item name="catch_phrase" xsi:type="string"><![CDATA[Find out your free Discount Code]]></item>
                                <item name="another_text" xsi:type="string"><![CDATA[I am another text !!!]]></item>
                                <item name="discount_code" xsi:type="string"><![CDATA[DISCOUNT50]]></item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

and our phtml file could be look like this :

<div id="training" data-bind="scope: 'myCustomComponent'">
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

<script type="text/x-magento-init">
        {
             "#training": {
                "Magento_Ui/js/core/app": <?php /* @noEscape */echo $block->getJsLayout(); ?>
            }
        }
</script>

Now we can work on our html file !

<div>
    <span data-bind="text: catch_phrase"></span>
</div>
<div>
    <span data-bind="text: code , visible :isShow"></span>
</div>
<div>
    <span data-bind="html: another_text"></span>
</div>
<div>
    <button data-bind="text: btnLabel , click: displayDiscountCode"></button>
</div>

the data-bind which are declared in our config will fill our HTML automatically. You can notice that there are different type such as text, html, visible , click.
If you want more information about the others kind of binding I let you check the knockout documentation

So if we consider what we see above, only catch_phrase and another_text are not mandatory to be declared in our Js.
Let’s create now our view js :

Menincode/Training/view/frontend/web/js/training.js
define([
    'ko',
    'jquery',
    'uiComponent',
    'Menincode_Training/js/model/training',
    'mage/translate'
], function (ko, $, Component, TrainingModel, $t) {
    'use strict';

    return Component.extend({

        catch_phrase: TrainingModel.catch_phrase,
        code: TrainingModel.code,
        btnLabel: ko.observable($t('Show Promo')),
        isShow: ko.observable(false),

        initialize: function () {
            // Do what you want at initialization
            this._super();
        },
        displayDiscountCode: function (config) {
            if (!this.isShow()) {
                TrainingModel.displayDiscountCode(config);
                this.btnLabel($t('Hide Promo'))
                this.isShow(true)
            } else {
                this.btnLabel($t('Show Promo'))
                this.isShow(false)
            }
        }
    });

});

the properties catch_phrase , and code are going to be provided by our model that we are going to make at the next step.
Just notice here, that we can initialize some data in our Js if we want.

btnLabel: ko.observable($t('Show Promo')),
isShow: ko.observable(false),

now let’s create our model js :

Menincode/Training/view/frontend/web/js/model/training.js
define([
    'jquery',
    'ko'
], function ($, ko) {
    'use strict'

    return {
        code: ko.observable(),

        displayDiscountCode : function (data){
            this.code(data.discount_code)
        }
    }
})

Here we just update our property code by what we have in our config.

Actually in this example, we could have simply bind our discount code into the html as far the discount code is not dynamic but I wanted to show you how to update an knockout observable 🙂

You have see how we can update a ko.observable. A ko.observable could be also an array. So you will have to do something like this :

myProperty : ko.observableArray([]),

myFunction : function (data){
this.myProperty.push(data)
}

Just hope that it helps you to understand a bit more about knockout !

Name (required)Email (required)Website

Leave a Reply