Magento2 How to Initialize JS Component Using Layout XML

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.

Step 1: Create our module registration php file as registration.php.

Location: app/code/Magemeta/CreateCustomer/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magemeta_CustomLayout',
    __DIR__
);

Location: app/code/Magemeta/CreateCustomer/etc/module.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magemeta_CustomLayout" setup_version="1.0.0"></module>
</config>

Location: app/code/Magemeta/CustomLayout/composer.json

{
    "name": "magemeta/module-custom-layout",
    "description": "This module is used to create customers",
    "type": "magento2-module",
    "license": "OSL-3.0",
    "authors": [
        {
            "email": "info@magemeta.com",
            "name": "magemeta"
        }
    ],
    "minimum-stability": "dev",
    "require": {},
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magemeta\\CustomLayout\\": ""
        }
    }
}

Step 2: We need to call our custom js renderer block into xml layout. Here we have use customer_account_edit.xml.

Location: app/code/Magemeta/CustomLayout/view/frontend/layout/customer_account_edit.xml

<?xml version="1.0"?>
<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="Magemeta\CustomLayout\Block\CustomLayout" name="magemeta_custom_layout" template="Magemeta_CustomLayout::custom_layout.phtml" cacheable="false">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="customcomponent" xsi:type="array">
                                <item name="component" xsi:type="string">Magemeta_CustomLayout/js/custom-component</item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Step 3: We need to create our custom block to collect information to insert into js layout.

Location: app/code/Magemeta/CustomLayout/Block/CustomLayout.php

<?php
/**
 * Magemeta_CustomLayout
 *
 * @category  Magemeta
 * @package   Magemeta_CustomLayout
 * @author    Magemeta Team <info@magemeta.com>
 * @copyright Copyright (c) 2019 Magemeta (http://www.magemeta.com)
 */

namespace Magemeta\CustomLayout\Block;

use Magemeta\CustomLayout\Model\CustomConfigProvider;
use Magento\Framework\View\Element\Template\Context;

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

    /**
     * @var CustomConfigProvider
     */
    protected $configProvider;

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

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

    public function getCustomConfig()
    {
        return $this->configProvider->getConfig();
    }
}

Step 4: We need to create model to collect and return configuration information to block.

Location: app/code/Magemeta/CustomLayout/Model/CustomConfigProvider.php

<?php
/**
 * Magemeta_CustomLayout
 *
 * @category  Magemeta
 * @package   Magemeta_CustomLayout
 * @author    Magemeta Team <info@magemeta.com>
 * @copyright Copyright (c) 2019 Magemeta (http://www.magemeta.com)
 */

namespace Magemeta\CustomLayout\Model;

class CustomConfigProvider implements ConfigProviderInterface
{
    /**
     * @var ConfigProviderInterface[]
     */
    private $configProviders;

    /**
     * @param ConfigProviderInterface[] $configProviders
     * @codeCoverageIgnore
     */
    public function __construct(
        array $configProviders
    ) {
        $this->configProviders = $configProviders;
    }

    /**
     * {@inheritdoc}
     */
    public function getConfig()
    {
        $config = [];
        foreach ($this->configProviders as $configProvider) {
            $config = array_merge_recursive($config, $configProvider->getConfig());
        }
        return $config;
    }
}

We also need to create model interface as ConfigProviderInterface.

Location: app/code/Magemeta/CustomLayout/Model/ConfigProviderInterface.php

<?php
/**
 * Magemeta_CustomLayout
 *
 * @category  Magemeta
 * @package   Magemeta_CustomLayout
 * @author    Magemeta Team <info@magemeta.com>
 * @copyright Copyright (c) 2019 Magemeta (http://www.magemeta.com)
 */

namespace Magemeta\CustomLayout\Model;

interface ConfigProviderInterface
{
    /**
     * Retrieve associative array of checkout configuration
     *
     * @return array
     */
    public function getConfig();
}

Step 5: Now we need to create our custom .phtml file as custom_layout.phtml. Here we initialized our custom component and load the custom js components by getJsLayout() method.

Location: app/code/Magemeta/CustomLayout/view/frontend/templates/custom_layout.phtml

<script>
    window.customConfig = <?php echo \Zend_Json::encode($block->getCustomConfig()); ?>;
</script>

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

Step 6: Now we need to create our custom js file

Location: app/code/Magemeta/CustomLayout/view/frontend/web/js/custom-component.js

define([
        'jquery',
        'uiComponent',
        'ko',
    ], function ($, Component, ko) {
        'use strict';
        var customConfigData = window.customConfig;
        return Component.extend({
            defaults: {
                template: 'Magemeta_CustomLayout/custom_layout'
            },

            initialize: function () {
                this._super();
            },
        });
    }
);

Step 7: Finally we need to create our custom custom_layout.html file if we set it component template part of custom-component.js. If you don't want to add template, just comment it out from js script.

Location: app/code/Magemeta/CustomLayout/view/frontend/web/template/custom_layout.html

<div class="customLayout">
    <p>This is custom layout html</p>
</div>

We are done with initializing the custom js component in custom layout.
Hope this helps you guys!

 

Leave a Reply