Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento
front end book you'll ever need. Get your copy
today!

Today we’re starting a new series that will cover advanced Javascript systems in Magento 2. This series is sponsored by my patreon campaign. If you like what you see here, please consider donating to keep the tutorials coming.

These commands should be familiar to anyone who’s worked their way through the Magento 2 for PHP MVC developers series. Once you’ve run the above, you should be able to access the following URL in your system

http://magento.example.com/pulsestorm_javascriptinittutorial/

and see the rendered app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml template.

Setting up a RequireJS Module

Now that we’ve setup a Magento module, lets do a quick review and create a RequireJS module. First, create the following file

This is a very simple RequireJS module. Due to the module’s location on the file system, and the way Magento loads javascript files, this module’s name/identifier is Pulsestorm_JavascriptInitTutorial/example

Next, change the contents of content.phtml so they match the following.

X-Magento-Init

The first initialization technique we’re going to discuss is the <script type="text/x-magento-init"> method. The most basic version of this initialization method allows you to run a RequireJS module as a program. Change the contents of the content.phtml template so they match the following

This tag is not a javascript tag. Notice the type="text/x-magento-init" attribute. When a browser doesn’t recognize the value in a script’s type tag, it will ignore the contents of that tag. Magento (similar to other modern javascript frameworks) uses this behavior to its advantage. While it’s beyond the scope of this tutorial, there’s Magento javascript code running that will scan for text/x-magento-init script tags. If you want to explore this yourself, this Stack Exchange question and answer is a good place to start.

The other part of the x-magento-init code chunk we can talk about immediately is the following object

Before we can talk about that, we’ll need to talk about javascript components.

Magento Javascript Components

The above example runs our RequireJS module as a program. This works, and Magento itself often uses the x-magento-init method to invoke a RequireJS module as a program. However, the real power of x-magento-init is the ability to create a Magento Javascript Component.

Magento Javascript Components are RequireJS modules that return a function. Magento’s system code will call this function in a specific way that exposes extra functionality.

If that didn’t make sense, try changing your RequireJS module so it matches the following.

Here we’ve defined a function and assigned it to a variable named mageJsComponent. Then, we return it.

If you reload the page with the above in place, you should see A Simple Magento Component in an alert box.

This may seem silly — what’s the point of returning a function if all Magento does is call it? You’d be right, but that’s because we left something out. Try changing our phtml template so it matches the following

If you reload the page, you should see the changed alert message. If you look in your browser’s javascript console, you should also see the following

> Object {config:"value"}

When we create a Magento Javascript Component, Magento calls the returned function and includes the object from text/x-magento-init.

"Pulsestorm_JavascriptInitTutorial/example":{"config":"value"}

This is why the RequireJS module name is a key — the value of this object is the object we want to pass to our component.

This may seem like a silly bit of abstraction in these examples. However, in a real module, we’d be generating that JSON with PHP. This system allows us to render the JSON in our phtml template, and then have that passed to Javascript code. This helps avoid the problem of generating Javascript directly with PHP, which can lead to very messy code, and makes it easy to accidentally slip in an error or security problem.

Before we finish up with x-magento-init, there’s one last feature to discuss. You’ll remember we said that x-magento-init

provides a way to pass that program a server side generated JSON object.

provides a way to provide that program with the DOM nodes it should operate on.

We’ve covered how to pass in server side generated JSON — but what about the DOM nodes?

What we’ve done here is add a second parameter to our mageJsComponent function. This second parameter will be the DOM node we want our program to operate on. However, if you reload the page with the above in place, you’ll see the following in your console.

> Object {config:"value"}
> false

Magento did pass in a value for node — but that value was false. What gives?

Here, we’ve changed the * to a #one. The * we used previously is actually a special case, for programs that don’t need to operate on DOM nodes. The key for this object is actually a CSS/jQuery style selector that tells Magento which DOM nodes the program in Pulsestorm_JavascriptInitTutorial/example should operate on. If we reload our page with the above in place, we’ll see the following in your console

By building this sort of system, Magento is encouraging developers to avoid hard coding their DOM nodes into their RequireJS modules. The x-magento-init means there’s a system level path forward for building Javascript modules that rely on server side rendered JSON, and operate on any arbitrary DOM node. It’s always been possible for Magento module developers to implement their own systems for this sort of functionality, but Magento 2 provides a standard, built in way to achieve this.

Data-mage-init Attribute

In addition to <script type="text/x-magento-init">, there’s another way to invoke similar functionality on a specific DOM node, and that’s with the data-mage-init attribute. Try replacing the existing phtml template with the following

Reload the page with the above in place, you should see the following in your javascript console.

> Object {another: "example"}
> <div>A single div</div>

Here, we’ve added a data-mage-init attribute to a specific div. This attribute’s value is a JSON object. Similar to x-magento-init, this object’s key is the RequireJS module we want to invoke as a program or Magento Javascript Component, and the value is a nested JSON object to pass into our Magento Javascript Component function as the config parameter.

On a pedantic note — you’ll notice we used single quotes with our attribute

<div data-mage-init='...'>A single div</div>

This is, unfortunately, required. The value of the data-mage-init attribute is parsed by a strict JSON parser, which means the JSON object’s quotes must be double quote — which means we can’t use double quotes for our attribute. While this is technically OK in HTML5, for web programmers of a certain age it brings back some bad Microsoft Frontpage memories.

Wrap Up

Whether you end up using the <script type="text/x-magento-init"> component or a data-mage-init attribute in a specific node, both these techniques provide a standard, system unified way of introducing Javascript entry points onto your page. Many of Magento’s front end and back end UI features rely on this syntax, so even if you personally eschew them, understanding how these systems work is an important part of being a Magento 2 developer.

Between these techniques and the base RequireJS implementation in Magento 2, we’re ready to cover our next topic — Magento 2’s use of the KnockoutJS library.