Magento 2 Mage Template

If you’ve been working with Magento 2 for a while you may have come across mage/template within the JavaScript files – it’s an area that isn’t covered all that well, at the time of writing I couldn’t find anything about it in the official documentation. It’s dotted about in the native code base, for example the product page tier pricing uses it. Today I’m going to show how it can be used and why you might want to use it.

What is it?

Essentially it allows us to setup a HTML template for some data that we later pass to it. It keeps the HTML markup out of the JavaScript file – which in itself has multiple benefits. For example you can easily adjust the template without having to touch a line of JavaScript, which is great for maintainability when you need to make changes further down the line.

It also prevents any complex JavaScript concatenation (when not using ES6 template literals), for example:

var template = '<div class="image">' +
'<img src="' + url + '" alt="' + altText + '" />' +
'</div>';

We’ve all been there, when there’s a lot of markup it can soon get out of hand and become difficult to manage.

By separating the template from the JavaScript file it also makes our module more useable. You can have one JavaScript file that outputs the data to the template, we can use different templates throughout the site giving you full control for individual instances, there’s no need to re-write the JavaScript file, you can use a different template for each instance if required.

Let’s see a working example.

Template File

First create a new file somewhere in your theme and get the block to display via XML. Within this file add the following contents:

Magento_Theme/templates/example.phtml

<div class="selector">
<h2><?= __('Images') ?></h2>
<div data-role="listing"></div>
</div>

<script type="text/x-magento-init">
{
".selector": {
"Magento_Theme/js/example": {
"template": "#custom-template",
"page": 1,
"limit": 5
}
}
}
</script>

<script type="text/x-magento-template" id="custom-template">
<% _.each(images, function(image) { %>
<div class="image-card">
<% if (image.download_url) { %>
<img src="<%= image.download_url %>" alt="<%= image.author %>" />
<% } %>

<% if (image.author) { %>
<h6><%= image.author %></h6>
<% } %>
</div>
<% }); %>
</script>

First we are initialising our new module using the text/x-magento-init method and passing some configuration.

Next we have our new template structured out within the text/x-magento-template script type. Notice it also has an id of custom-template which we pass to the module as a config value "template": "#custom-template" – this gets used within the JavaScript file we’ll be creating next.

The syntax for the custom template looks a bit funky and takes some getting used to. We are looping over the data that we pass through from the JavaScript file, when rendering the data it’s a good idea to add conditions around the values in case the data structure changes in the future to help prevent any fatal errors.

JavaScript File

Now create the JavaScript file for the module:

Magento_Theme/web/js/example.js

define([
'jquery',
'mage/template'
], function ($, mageTemplate) {
'use strict';

var imagesModule = function (config, element) {
var page = config.page ? config.page : 1;
var limit = config.limit ? config.limit : 10;

// get the data from url
$.ajax({
url: 'https://picsum.photos/v2/list',
type: 'GET',
data: {
page: page,
limit: limit
}
}).done(function (data) {
// if no template, do nothing
if (!config.template) return;

var $element = $(element);

// setup the template
var template = mageTemplate(config.template);

// pass the data to the template
var templateHtml = template({
images: data
});

// inject the html to the selector
$element.find('[data-role="listing"]').html(templateHtml);
});
};

return imagesModule;
});

First we setup mage/template as a dependency and map it to mageTemplate. Then we setup the structure for the module, I’m using a public API endpoint as an example to retrieve some images which we’ll be using as our data.

Within the jQuery Ajax call, once we have the data we work it into the template file which involves these lines:

// setup the template 
// config.template = #custom-template (our script tag)
var template = mageTemplate(config.template);

// pass the data to the template
// assign the data to images which we loop over in our template
var templateHtml = template({
images: data
});

// inject the html to the selector
$element.find('[data-role="listing"]').html(templateHtml);

We setup the mageTemplate by passing the id of the script tag we setup earlier. Then we can send our template some data, in this example we are only sending images but you can send multiple key value pairs if required. Lastly the populated HTML is injected to the div with a data-role of listing.

You should now have a list of images rendering on the page that uses the template structure for each item. It’s a clean way of managing templates for JavaScript data – let me know your thoughts on Twitter and any good examples you’ve come up with.