Magento 2 Get JS Layout

When configuring your JavaScript file its usually added where your calling it from, in the script tag or in the data-mage-init attribute. For Magento UI components things tend to work a bit differently as it uses XML for the configuration by using the $block->getJsLayout() which is a nice way of doing it as it keeps your template files free from configuration which in some cases can get quite lengthy and not very manageable. Let’s take some basic examples below to compare.

Regular JavaScript configuration:

<div id="selector">...</div>

<script type="text/x-magento-init">
{
"#selector": {
"Magento_Theme/js/example": {
"optionOne": "valueOne",
"optionTwo": "valueTwo"
}
}
}
</script>

Magento UI component configuration:

<div id="selector">...</div>

<script type="text/x-magento-init">
{
"#selector": {
"Magento_Ui/js/core/app": <?= /* @escapeNotVerified */ $block->getJsLayout() ?>
}
}
</script>
<block name="example" template="Magento_Theme::example.phtml">
<arguments>
<argument name="jsLayout" xsi:type="array">
<!-- add config here -->
</argument>
</arguments>
</block>

For the Magento UI component you can see that all the configuration can be loaded with one line, which in turn grabs it from the associated XML block.

When searching through the Magento codebase $block->getJsLayout() is only ever used in connection with Magento UI components and if you search for it on the web you’ll find results only to do with Magento UI components.

This got me thinking, why don’t we use this for regular JavaScript files? It would be nice on some occasions to configure the JavaScript via XML. I’m surprised this isn’t documented anywhere (as far as I’m aware) and I don’t see why it would be an issue to use it outside of the Magento UI component realm.

I’ve put together a quick demo of how this could be used using the Modal widget as an example.

Configuration

First we’ll create an example block via XML, place this block anywhere you want it to display within your theme:

<block name="example" before="-" template="Magento_Theme::example.phtml">
<arguments>
<!-- arguments for .phtml file -->
<argument name="trigger_text" translate="true" xsi:type="string">Trigger Text</argument>

<!-- config rendered by $block->getJsLayout() -->
<argument name="jsLayout" xsi:type="array">
<item name="autoOpen" xsi:type="boolean">true</item>
<item name="buttons" xsi:type="array">
<item name="buttonOne" xsi:type="array">
<item name="text" translate="true" xsi:type="string">Button One</item>
<item name="class" xsi:type="string">button-one-class</item>
</item>
<item name="buttonTwo" xsi:type="array">
<item name="text" translate="true" xsi:type="string">Button Two</item>
<item name="class" xsi:type="string">button-two-class</item>
</item>
</item>
<item name="closeText" translate="true" xsi:type="string">Close</item>
<item name="clickableOverlay" xsi:type="boolean">true</item>
<item name="focus" xsi:type="string">[data-role="closeBtn"]</item>
<item name="innerScroll" xsi:type="boolean">false</item>
<item name="modalClass" xsi:type="string">modalClass</item>
<item name="modalLeftMargin" xsi:type="number">45</item>
<item name="responsive" xsi:type="boolean">false</item>
<item name="title" translate="true" xsi:type="string">Modal Title</item>
<item name="type" xsi:type="string">popup</item>
</argument>
</arguments>

<!-- modal contents, static cms block -->
<block class="Magento\Cms\Block\Block" name="modal.content">
<arguments>
<argument name="block_id" xsi:type="string">contact-us-info</argument>
</arguments>
</block>
</block>

Here we have added a whole bunch of arguments which we’ll be using in our template file next and passing it through to our JavaScript file.

Template File

Next we’ll create the template file which will render the markup and load the configuration in:

<ThemeName>/Magento_Theme/templates/example.phtml
<div id="selector">
<button type="button" data-role="trigger">
<?= $block->getTriggerText() ?>
</button>

<div data-role="target" style="display: none;">
<?= $block->getChildHtml(); ?>
</div>
</div>

<script type="text/x-magento-init">
{
"#selector": {
"Magento_Theme/js/modal": <?= /* @escapeNotVerified */ $block->getJsLayout() ?>
}
}
</script>

Here we are adding in a button for the trigger and getting the button text from the XML argument called trigger_text.

For the contents of the modal we are using the Static CMS block we defined in our XML file which is hidden on the page by default. When you don’t pass a value to $block->getChildHtml() it will render all child blocks specified in the XML file.

Lastly we are using $block->getJsLayout() to render the configuration from our XML argument called jsLayout.

JavaScript File

Finally we’ll create the JavaScript file which will provide the functionality:

define([
'jquery',
'Magento_Ui/js/modal/modal'
], function ($) {
'use strict';

var modal = function (config, element) {
var $el = $(element);
var trigger = $el.find('[data-role="trigger"]');
var target = $el.find('[data-role="target"]');
var buttons = [];

// setup buttons
if (config.buttons) {
for (var prop in config.buttons) {
if (config.buttons.hasOwnProperty(prop)) {
var button = config.buttons[prop];

buttons.push({
text: button.text,
class: button.class,
click: function () {
this.closeModal();
}
});
}
}
}

// setup modal
target.modal({
autoOpen: config.autoOpen,
buttons: buttons,
closeText: config.closeText,
clickableOverlay: config.clickableOverlay,
focus: config.focus,
innerScroll: config.innerScroll,
modalClass: config.modalClass,
modalLeftMargin: config.modalLeftMargin,
responsive: config.responsive,
title: config.title,
type: config.type,
});

// setup trigger
$(trigger).on('click', function () {
target.modal('openModal');
});
};

return modal;
});

Within our JavaScript file we are adding in the Modal widget as a dependency and using the config and element that gets passed through for our functionality. We have full access to the configuration which gives us greater flexibility when using this feature and allows us to fully customise the Modal for different instances via XML.

You should now have a working Modal on your page, try changing the configuration in the XML for different scenarios and see it update.

This article was to demonstrate that $block->getJsLayout() is not just for Magento UI components – even though it seems Magento only uses it for this – but it can be used for regular JavaScript features too.