Skip to content

x-magento-template and mage/template

Sometimes underscore.js templates are used in Luma.

Most of the time this happens through the utility JavaScript module mage/template.

Since mage/template and underscore.js are not used in Hyvä, these template-snippets are replaced with Alpine.js templates.

Underscore templates are useful to create new DOM nodes for each item in an array. They might also be used for the plain rendering some data available in JavaScript in HTML, but that use case is not covered here since it can be replaced by plain Alpine.js directives like x-html and x-text.

In Alpine.js array items are rendered using x-for directives.

Recap of mage/template

It is helpful to have some understanding of Luma code when converting it to Alpine.js.

In this spirit, this mage/template recap is intended to help you in the conversion process.

Commonly the templates are written as <script id="selector" type="text/x-magento-template"> elements in .phtml files.

The selector is often an ID attribute, but sometimes it can also be a something like data-role="myTemplate".

Here is an example of how mage/template is used in Luma (in the following example it is assigned to the template variable):

$(template(tmplSelector, {
    data: config
})).appendTo(body);

Under the hood, these templates are rendered using the underscore.js template() function.

The underscore.js template() function "compiles" the template content into a rendering function, which is then called with a data object containing the variables to be rendered.

var tplString = document.querySelector(selector).innerHTML;
var render = _.template(tplString);
var output = render(data);
return output;

More details on the template syntax can be found in the underscore.js template documentation.

Rendering array items with Alpine.js

In Alpine.js array items are rendered using the x-for directive:

<ul class="bundle items">
    <template x-for="option in selectedOptions">
    <li class="mb-2" x-show="option.products.length">
        <span class="text-base font-semibold" x-html="option.label"></span>
        <template x-for="product in option.products">
            <div><span x-html="product.qty"></span> x <span x-html="product.name"></span></div>
        </template>
    </li>
    </template>
</ul>

As you can see in the example above, x-for directives can be nested.

Finally, a note straight from the Alpine.js documentation:

If you want to access the current index of the iteration, use the following syntax:

<template x-for="(product, index) in products" :key="index">
    <span :class="{
                'bg-opacity-100': active === index,
                'hidden': (pageSize !== 1 && !!(index % pageSize))
         }"
        @click="getSlider().scrollLeft =
            (getSlider().scrollWidth / products.length) * index; active=index;">
    </span>
</template>

More details can be found in the Alpine.js x-for documentation.