Back to Top

How to Intialize Js Component Using Layout XML in Magento2

Updated 22 February 2024

How to use Initialize Js Component on custom phtml file using layout xml in Magento2

In Magento2 mainly we have seen on checkout page all Js components loads using xml, these components are defined in checkout_index_index.xml file.

We can also define our custom Js Components using our xml Layout File.

1. Let’s create our required xml file: Webkul/CustomJs/view/frontend/layout/customjs_index_index.xml

<?xml version="1.0"?>
<!--
/**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomJs
 * @author    Webkul
 * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="customer_account"/>
    <body>
        <referenceContainer name="content">
            <block class="Webkul\CustomJs\Block\CustomJs" name="customjs_test" template="Webkul_CustomJs::account/customjs.phtml" cacheable="false">
            </block>
        </referenceContainer>
    </body>
</page>

2. Let’s create our required Controller file: Webkul/CustomJs/Controller/Index/Index.php

<?php
namespace Webkul\CustomJs\Controller\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;

/**
 * Webkul Marketplace Landing page Index Controller.
 */
class Index extends Action
{
    /**
     * @var PageFactory
     */
    protected $resultPageFactory;

    /**
     * Constructor
     *
     * @param Context $context
     * @param PageFactory $resultPageFactory
     */
    public function __construct(
        Context $context,
        PageFactory $resultPageFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    /**
     * Execute Action
     *
     * @return void
     */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        $resultPage->getConfig()->getTitle()->set(__('Custom JS'));

        return $resultPage;
    }
}

3. Create Block file Webkul/CustomJs/Block/CustomJs.php

Searching for an experienced
Magento 2 Company ?
Find out More
<?php
/**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomJs
 * @author    Webkul
 * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
namespace Webkul\CustomJs\Block;

class CustomJs extends \Magento\Framework\View\Element\Template
{
    /**
     * @var array
     */
    protected $jsLayout;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        array $data = []
    ) {
        parent::__construct($context, $data);
        $this->jsLayout = isset($data['jsLayout']) && is_array($data['jsLayout']) ? $data['jsLayout'] : [];
    }

    /**
     * @return string
     */
    public function getJsLayout()
    {
        return \Zend_Json::encode($this->jsLayout);
    }
}

4. Now we need to create our phtml file Webkul/CustomJs/view/frontend/templates/account/customjs.phtml

<div id="customjs-component" data-bind="scope:'custom-js-field'">
    <!-- ko template: getTemplate() --><!-- /ko -->
    <script type="text/x-magento-init">
    {
        "#customjs-component": {
            "Magento_Ui/js/core/app":  <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
        }
    }
    </script>
</div>

Ok, now takes a closer look on above code.
we have initialized our custom compenent and load the js components by getJsLayout() Method.

You can see we have defined this Method in our Block File, which is providing Js layouts.
But we haven’t defined jsLayout in our customjs_index_index.xml file yet.

Let’s open it again and update with this code.

<?xml version="1.0"?>
<!--
/**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomJs
 * @author    Webkul
 * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="customer_account"/>
    <body>
        <referenceContainer name="content">
            <block class="Webkul\CustomJs\Block\CustomJs" name="customjs_test" template="Webkul_CustomJs::account/customjs.phtml" cacheable="false">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="custom-js-field" xsi:type="array">
                                <item name="component" xsi:type="string">uiComponent</item>
                                <item name="config" xsi:type="array">
                                    <item name="template" xsi:type="string">Webkul_CustomJs/js-group</item>
                                </item>
                                <item name="children" xsi:type="array">
                                    <item name="my-child-js" xsi:type="array">
                                        <item name="sortOrder" xsi:type="string">1</item>
                                        <item name="component" xsi:type="string">Webkul_CustomJs/js/view/my-child-js</item>
                                        <item name="displayArea" xsi:type="string">my-child-js</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Now what we really did here,
We have defined the jsLayout as arguments, so we can get all these arguments in our Block File as

$this->jsLayout = isset($data['jsLayout']) && is_array($data['jsLayout']) ? $data['jsLayout'] : [];

You will see that all the components with its children nodes are assigned to “Magento_Ui/js/core/app.js” component.

We have called a function getTemplate() in our phtml file

When this method is called Magento checks for the template defined in custom-js-field scope which we have defined as attribute in our phtml file

<div id="customjs-component" data-bind="scope:'custom-js-field'">

We have also defined children components in our customjs_index_index.xml file, let learn how we can use them as well.

Let create Html template file Webkul/CustomJs/view/frontend/web/template/js-group.html which we have defined.

<item name="components" xsi:type="array">
    <item name="custom-js-field" xsi:type="array">
        <item name="component" xsi:type="string">uiComponent</item>
        <item name="config" xsi:type="array">
            <item name="template" xsi:type="string">Webkul_CustomJs/js-group</item>
        </item>

Open this file and update with this code.

<!-- 
    /**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomJs
 * @author    Webkul
 * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
 -->
 
<!-- ko foreach: getRegion('my-child-js') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->

When this template load it will look for the area with name my-child-js in customjs_index_index.xml file.

we already defined it in our xml file.

<item name="children" xsi:type="array">
    <item name="my-child-js" xsi:type="array">
        <item name="sortOrder" xsi:type="string">1</item>
        <item name="component" xsi:type="string">Webkul_CustomJs/js/view/my-child-js</item>
        <item name="displayArea" xsi:type="string">my-child-js</item>
    </item>
</item>

Children items can also contains define component, we can define nested children as many as we want.

Now, we need to create Webkul/CustomJs/view/frontend/web/js/view/my-child-js.js file

/**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomJs
 * @author    Webkul
 * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
/*jshint browser:true jquery:true*/
/*global alert*/

define(['jquery', 'uiComponent', 'ko'], function ($, Component, ko) {
    'use strict';
    return Component.extend({
        defaults: {
            template: 'Webkul_CustomJs/view/my-child-js'
        },
        initialize: function () {
            this.customerName = ko.observableArray([]);
            this.customerData = ko.observable('');
            this._super();
        },

        addNewCustomer: function () {
            this.customerName.push({name:this.customerData()});
            this.customerData('');
        }
    });
});

In this case, we call html template from our js component by passing template key with value on defaults object.
Also, we can call same html template file from xml for example:

<item name="config" xsi:type="array">
    <item name="template" xsi:type="string">Webkul_CustomJs/js-group</item>
 </item>

Now, we need to create html template Webkul/CustomJs/view/frontend/web/template/view/my-child-js.html file

<div class="component-wrapper">
    <div class="field">
        <label class="label" for="email"><span data-bind="i18n: 'New Record'"></span></label>
        <div class="control">
            <input name="customername"
                   id="customername"
                   type="text"
                   class="input-text"
                   data-bind="value: customerData">
        </div>
    </div>
    <div class="primary">
        <button type="button" class="action action-login secondary" data-bind="click: addNewCustomer">
            <span data-bind="i18n: 'Save'"></span>
        </button>
    </div>

    <div class="customer-list" style="width: 20%;background: gray;margin-top: 10px;" data-bind="foreach: customerName">
        <li data-bind="text: name"></li>
    </div>
</div>

That’s it!

. . .

Leave a Comment

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


1 comments

  • Sasikiran Kesavan
  • Back to Top

    Message Sent!

    If you have more details or questions, you can reply to the received confirmation email.

    Back to Home