UI Component using Layout XML in Magento 2

Posted on 9 February, 2019

In Magento2, you can initialize js components using layout XML. The place where it’s used more is the checkout page, in the checkout_index_index.xml file. The main advantage of initializing js component using layout XML is extensibility. Using component in phtml would require overriding template file for modification. As, Magento2 parses the XML file of all modules and merge it into one to read it's configuration, so we are able to extend & modify configuration easily. XML file is parsed into a JSON object which is passed into the main component when it is initialized. We can also pass configuration to the component from the XML file. These configurations are then added to the component object. So let’s start with the steps

Create app/code/Emipro/Knock/view/frontend/layout/knock_index_index.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Emipro\Knock\Block\Index\Index" name="knock_index_index" template="Emipro_Knock::knock_index_index.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                         <item name="emipro-knockout" xsi:type="array">
                            <item name="component" xsi:type="string">Emipro_Knock/js/emiproko</item>
                            <item name="template" xsi:type="string">Emipro_Knock/kotemplate</item>
                            <item name="config" xsi:type="array">
                                    <item name="custommessage" xsi:type="string" translate="true">Emipro</item>
                          </item>
                        </item>
                         </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Under block, add argument named "jsLayout" of type array, under which you have to pass components, after this, all will be same as we write in phtml. You can also pass value from Layout XML, for example, custommessage in our case. Refer How to use Knockout in Magento 2 about using phtml to add component.

For example in phtml above thing is added as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script type="text/x-magento-init">
    {
        "*": {
                "Magento_Ui/js/core/app":
                  {
                      "components":
                      {
                          "emipro-knockout":
                          {
                                 "component":"Emipro_Knock/js/emiproko",
                                 "template":"Emipro_Knock/kotemplate",
                                  "config":
                                  {
                                          "custommessage":"Emipro"
                                   }
                          }
                        }
                  }
            }
    }
</script>

Create app/code/Emipro/Knock/view/frontend/templates/knock_index_index.phtml:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="emipro-knockout" data-bind="scope:'emipro-knockout'">
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>
<script type="text/x-magento-init">
    {
        "*":
         {
            "Magento_Ui/js/core/app":  <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
         }
    }
</script>

app.js(Magento_Ui/js/core/app) injects the layout renderer which contains all the components that need to be rendered. The renderer then loops through each of these components & render it one by one, including the children component. You can also add dependencies within the XML, to make sure that a particular component will be initialized before other components.

Create app/code/Emipro/Knock/view/frontend/web/js/emiproko.js

1
2
3
4
5
6
7
8
define(['uiComponent'], function(Component) {
        return Component.extend({
            getText: function () {
                return "Js layout example";
            }
        });
});

Create app/code/Emipro/Knock/view/frontend/web/template /kotemplate.html

1
2
<div class="emipro-knockout-example" data-bind="text:getText()"></div>
<div data-bind="text:custommessage"></div>

Define Child Component

Update app/code/Emipro/Knock/view/frontend/layout/knock_index_index.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="sidebar.main">
            <block class="Emipro\Knock\Block\Index\Sidebar" name="knock_index_sidebar" before="-" template="Emipro_Knock::knock_index_sidebar.phtml"/>
        </referenceContainer>
        <referenceContainer name="content">
            <block class="Emipro\Knock\Block\Index\Index" name="knock_index_index" template="Emipro_Knock::knock_index_index.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                         <item name="emipro-knockout" xsi:type="array">
                            <item name="component" xsi:type="string">Emipro_Knock/js/emiproko</item>
                            <item name="template" xsi:type="string">Emipro_Knock/kotemplate</item>
                            <item name="config" xsi:type="array">
                                    <item name="custommessage" xsi:type="string">Emipro</item>
                          </item>
                            <item name="children" xsi:type="array">
                                    <item name="emipro-child-ko" xsi:type="array">
                                        <item name="sortOrder" xsi:type="string">1</item>
                                        <item name="component" xsi:type="string">Emipro_Knock/js/childko</item>
                                        <item name="displayArea" xsi:type="string">child-ko</item>
                                    </item>
                                </item>
                        </item>
                         </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

You can add as many as component under children attribute & each one will be rendered using sortOrder. Component reads & render templates using getRegion(). displayArea attribute represents tothe region in getRegion() (The value added in displayArea will be added inside getRegion()).

Update app/code/Emipro/Knock/view/frontend/web/template/kotemplate.html by adding this:

1
2
3
<!-- ko foreach: getRegion('child-ko') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->

Create  app/code/Emipro/Knock/view/frontend/web/js/childko.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
define([
    'jquery',
    'uiComponent',
    'ko',
], function ($, Component, ko) {
        'use strict';
        return Component.extend({
            defaults: {
                template: 'Emipro_Knock/child-ko'
            },
           getChildText: function () {
                return "text from child js";
            },
        });
    });

You can also define template from js inside defaults as shown in above example.

Create app/code/Emipro/Knock/view/frontend/web/template/child-ko.html

1
2
<h2>Child KO </h2>
<div class="emipro-knockout-example" data-bind="text:getChildText()"></div>

That’s it! Hope this helped you. If you have any questions or comments, feel free to post in the comment section.


Mona Mehta , Senior eCommerce Developer

Magento Technical Notes

About Emipro

Being an emerging leader in IT market since 2011, Emipro Technologies Pvt. Ltd. has been providing a wide range of business solutions in Odoo & Magento. We are pleased to have a large pool of contented customers with our meticulous work in the domain of ERP & e-Commerce. Our customers are companies of all sizes ranging from startups to large enterprises who realize that they need a professional internet solution to generate revenue streams, establish proper communication channels, to achieve desired goals and streamline business operations. [....] Read More

Our writings seems informative ?

Subscribe for our Magento Technical Notes and get more amazing stuff directly to your inbox!

Post Your Review

X

Your Review has been posted

0 Comment(s)