junmindereal
8/19/2019 - 3:31 AM

Magento2 - UI Component: getJsLayout, CustomData

Final Control Point

Layout

Important: Do not override the vendor/magento layout. Just extend them

Change/Create a Container/Block

Create a container

<container name="product.info.form.content" as="product_info_form_content">
    ...
</container>

Create a block

<block class="Magento\Framework\View\Element\Template" name="test.ui.component" template="Magento_Theme::block.phtml">
    ...
</block>

Reference a Container/Block

Reference Container

<referenceContainer name="content">
    ...
</referenceContainer>

Reference Block

<referenceBlock name="report.bugs"/>

Move a Container/Block

<move element="product.info.stock.sku" destination="product.info.price" after="product.price.final"/>

Remove a Container/Block

<referenceBlock name="breadcrumbs" remove="true" />

Override/Extend layout.xml

Note: In this example I will use the Magento_Theme module

  • Under ../[VendorName]/[ThemeName]/Magento_Theme/layout create a layout named default.xml.
  • Add your new updates in it
    <?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">
    <body>
        <referenceBlock name="report.bugs" remove="true" />
    </body>
    </page>
    

page_layout

The purpose of page layouts is to create a structured, common set of layout instructions to render pages. Most pages on a website can be categorized as fitting into a 1, 2, or 3-column container system. These page layouts can be selected in the admin panel to provide a specific layout per page.

We Can Create a sample file in here

../[VendorName]/[ThemeName]/Magento_Catalog/page_layout/2columns-left.xml

<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
    <update handle="1column"/>
    <referenceContainer name="columns">
        <container name="div.sidebar.main" htmlTag="div" htmlClass="sidebar sidebar-main" after="main">
            <container name="sidebar.main" as="sidebar_main" label="Sidebar Main"/>
        </container>
        <container name="div.sidebar.additional" htmlTag="div" htmlClass="sidebar sidebar-additional" after="div.sidebar.main">
            <container name="sidebar.additional" as="sidebar_additional" label="Sidebar Additional"/>
        </container>
    </referenceContainer>
</layout>

layout_handler / layout handles

<?xml version="1.0"?>

<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="mage/gallery/gallery.css"/>
    </head>
    <!-- Extends the layout -->
    <update handle="catalog_product_opengraph" />
    <update handle="page_calendar"/>
    <body>
    </body>
</page>

The specified handle is “included” and executed recursively.

Note:

  • page_layout is the layout of the whole page
  • layout is the layout of a certain section of a page

default.xml and default_head_blocks.xml

default.xml hold the page containera, blocks, arguments, template, and so on

<?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">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template" name="test.ui.component" template="Magento_Theme::block.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="test-ui-component" xsi:type="array">
                                <item name="component" xsi:type="string">Magento_Theme/js/view/sample-component</item>
                                <item name="config" xsi:type="array">
                                    <item name="template" xsi:type="string">Magento_Theme/sample-ui-template</item>
                                </item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

default_head_blocks.xml holds the dependencies

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <!-- Add local resources -->
        <css src="css/my-styles.css"/>
        <!-- The following two ways to add local JavaScript files are equal -->
        <script src="Magento_Theme::js/sample1.js"/>
        <script src="http://127.0.0.1:35729/livereload.js" src_type="url"></script>

        <link src="js/sample.js"/>
        <!-- Add external resources -->
        <link rel="stylesheet" type="text/css" src="http://fonts.googleapis.com/css?family=Montserrat" src_type="url" />
    </head>
</page>

How to pass argument in layout.xml files

<?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">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template" name="test.ui.component" template="Magento_Theme::block.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="test-ui-component" xsi:type="array">
                                <item name="component" xsi:type="string">Magento_Theme/js/view/sample-component</item>
                                <item name="config" xsi:type="array">
                                    <item name="template" xsi:type="string">Magento_Theme/sample-ui-template</item>
                                </item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

template

Create template

Under ../[VendorName]/[ThemeName]/Magento_Catalog/templates create a file called test-block.phtml

<?php
/**
 * @var \Ewave\MagentoCatalog\Block\TestBlock $block
 */

?>

<div class="block custom-block">
    <h4 class="block-title">Good day!</h4>
</div>

<div class="block custom-block">
    <h4 class="block-title">Test JS translation</h4>
    <p id="translate-js"></p>
</div>

<h4 class="block-title"><?= /* @escapeNotVerified */ __('translated_title') ?></h4>

<h6>(1)object</h6>
<p data-mage-init='{"mystyle": {"color": "yellow"}}'>I am color Yellow <code>data-mage-init</code></p>

<h6>(2)function</h6>
<p data-mage-init='{"mystyle2": {"background": "blue"}}'>I have a blue background <code>data-mage-init</code></p>

<p><?= $block->getData('display_text') ?></p>

<p><?= $block->getDisplayText() ?></p>

Override template

Under ../[VendorName]/[ThemeName]/Magento_Checkout/web/template/minicart create a file similar to the vendor file named content.html and move parts.

<!-- I just moved this part somewhere in this file -->
<!-- ... -->
<if args="getCartParam('summary_count')">
    <strong class="subtitle" translate="'Recently added item(s)'"/>
    <div data-action="scroll" class="minicart-items-wrapper">
        <ol id="mini-cart" class="minicart-items" data-bind="foreach: { data: getCartItems(), as: 'item' }">
            <each args="$parent.getRegion($parent.getItemRenderer(item.product_type))"
                    render="{name: getTemplate(), data: item, afterRender: function() {$parents[1].initSidebar()}}"
            />
        </ol>
    </div>
</if>
<!-- ... -->

Style

Extend less file

Under ../[VendorName]/[ThemeName]/web/css/source we can create a file called _extend.less

And we can also create another directory in ../source like /extend and create the file you wish to extend like _block.less and import it to the _extend.less file

@import 'extend/_block.less';

Note: You can also add specific _extend.less files in specific modules


JS Widget

Create a widget based on jqueryUI (AMD Module)

<h2>accordion</h2>
<div id="accordion" data-mage-init='{ "accordion": {} }'>
    <div data-role="collapsible">
        <div data-role="trigger">
            <span>Title 1</span>
        </div>
    </div>
    <div data-role="content">Content 1</div>

    <div data-role="collapsible">
        <div data-role="trigger">
            <span>Title 2</span>
        </div>
    </div>
    <div data-role="content">Content 2</div>

    <div data-role="collapsible">
        <div data-role="trigger">
            <span>Title 3</span>
        </div>
    </div>
    <div data-role="content">Content 3</div>
</div>

<!-- init method 1 : data-mage-init='{ "accordion": {} }' -->

<!-- init method 2  -->
<script>
    require([
        'jquery',
        'accordion'], function ($) {
        $("#accordion").accordion();
    });
</script>

<!-- <script type="text/x-magento-init">
{
    "#accordion": {
        "accordion": {}
    }
}
</script> -->

Add a widget mixin

note: A common method to extend a widget is adding a mixin

var config = {
    config: {
        mixins: {
            "Magento_Catalog/js/mystyle": {
                "Magento_Catalog/js/mystyle-mixins": true
            }
        }
    }
}

Add a widget into requirejs-config.js

var config = {
    map: {
        "*": {
            mystyle: "Magento_Catalog/js/mystyle",
            mystyle2: "Magento_Catalog/js/mystyle2",
        }
    }
}

2 methods to call JS-widget in html/phtml template

By using a object

<h6>(1)object</h6>
<p data-mage-init='{"mystyle": {"color": "yellow"}}'>I am color Yellow <code>data-mage-init</code></p>
define(['jquery'], function ($) {
    'use strict';

    return {
        'mystyle': function (config, element) {
            $(element).css('color', config.color);
        }
    };
});


By using a function

<h6>(2)function</h6>
<p data-mage-init='{"mystyle2": {"background": "blue"}}'>I have a blue background <code>data-mage-init</code></p>
define(['jquery'], function ($){
    'use strict';

    return function(config, element) {
        $(element).css('background', config.background);
    }
});

Translation

In php template

By using this __('translated_title')

<h4 class="block-title"><?= /* @escapeNotVerified */ __('translated_title') ?></h4>

en_US.csv file under ../[VendorName]/[ThemeName]/i18n

"translated_title","I am translated title"

In an argument in layout files

By adding translate="true"

<referenceBlock name="ThemeTest.test-block">
    <arguments>
        <argument name="display_text" xsi:type="string" translate="true">Hello</argument>
    </arguments>
</referenceBlock>

en_US.csv file under ../[VendorName]/[ThemeName]/i18n

"Hello", "kamusta"

in JS

Create a file under ../<Module_Name>/web/js

In this example I create a file named mytranslation.js

require([
    'jquery',
    'mage/translate'
    ], function ($, __) {
    setTimeout(() => {
        $('#translate-js').text('script-translate: ' + $.mage.__('translate_js'));
    }, 1000);
});
"translate_js","Translated through javascript"

UI Component

How to create

Create a file under ../[VendorName]/[ThemeName]/<Module_Name>/web/js/view

In this example, I create a file named plain-view-model.js

define([], function() {
    'use strict';

    return function (config) {
        return {
            title: 'This text is from plain-view-model.js',
            config: config
        }
    }
});

How to extend

We can extend our UI Component by using <script type="text/x-magento-init">

<h2>Plain View Model</h2>

<div class="example" data-bind="scope: 'plainViewModel'">
    <h5 data-bind="text: title"></h5>
    <h5 data-bind="text: config.label"></h5>
    <pre data-bind="text: JSON.stringify(config, null, 2)"></pre>
</div>

<script type="text/x-magento-init">
    {
        "*": {
            "Magento_Ui/js/core/app": {
                "components": {
                    "plainViewModel": {
                        "component": "Magento_Theme/js/view/plain-view-model",
                        "label": "This is the label"
                    }
                }
            }
        }
    }
</script>