The concept of “observables” can be a little tricky to wrap your head around in Knockout.js. Today we’re going to have a quick tutorial on how observables work outsidethe context of a normal Knockout.js view. We need to do this because Magento 2’s javascript frameworks make heavy use of observables that goes above and beyond what a normal front end developer needs to be aware of.

If you’re trying to think rationally about your Magento systems, you’ll not only need to understand how observables work, but you’ll often need to know how the internals are implemented.

What are Observables

Observables are stand-alone setter/getter objects. From a Magento bootstrapped page, run the following code in your browser’s javascript console. You should also be able to do this outside of Magento in systems that use a global ko variable instead of Magento’s special RequireJS module.

//load the Knockout.js library -- normally you'd do this in a `define`
ko =requirejs('ko');
//create the observable object with a default valuevar objectToHoldMyValue = ko.observable('default value');
//fetch that value by calling the observable as a function
console.log( 'Value: '+objectToHoldMyValue() );
"default value"//set a new value by calling the observable as a function with an argumentobjectToHoldMyValue('new value')
//fetch that value by calling the observable as a function
console.log( 'Value: '+objectToHoldMyValue() );
"new value"

As you can see from the above code and comments, the first job of an observable object is to store a value, return a value, and change a stored value. The syntax may be a little weird if you’re not used to the “objects can be anonymous functions” nature of javascript, but this is nothing too crazy. Also — nothing too necessary either, until you consider subscribers.

The above code sets up a callback that is, in other terms, an event listener (i.e. you’re subscribing to an event). The event you’re subscribing to? A change in value of the observable. If you run the value setting code again.

objectToHoldMyValue('a second new value')
The subscriber sees: a second new value

you’ll see Knockout calls your subscriber method.

Important: Subscribers are only called when a value changes. If you pass in the observable’s current value, Knockout will not call subscriber callbacks

objectToHoldMyValue('a third new value')
The subscriber sees: a third new value
objectToHoldMyValue('a third new value')
[no output, because the subscriber was not called]

While our example is a little silly, in a real program observables let you take actions whenever the value of a variable changes. That’s an incredibly powerful feature.

The Importance of Observables

Observables are what enables Knockout’s “update the model, automatically update the UI” behavior. If you consider a simple Knockout.js data binding (from the official intro tutorial)

<input data-bind="value: firstName" ... />

Behind the scenes, the value data-binding will check if firstName is an observable. IffirstName is an observable, the value binding implementation will setup a subscriber that updates the <input/>. This means whenever a programmer updates the value stored infirstName, the binding’s subscriber runs, and the <input/>‘s value is updated.

Knockout.js does all this behind the scenes. Even if you create a custom binding, Knockout handles setting up the subscriber, and your binding’s update method gets called. There’s no need for you, as a binding developer, to know about subscribers.

The subscribe method feels like something that should be a private API, but since this is javascript and everything’s public by default, developers can and will setup their own subscribers for observables.

Something else that may cause you, as a javascript or PHP programmer, a bit of cognitive dissonance is the lack of empty parameter () parenthesis when someone uses an observable in a data binding

<input data-bind="value: firstName" ... />

When I first started with Knockout.js, the lack of any clear distinction between a regular object property and an observable — at the template level — was a little confusing. Once you understand that observables are just callable javascript objects, and understand that the binding needs to receive this object and not its stored value, things start to make a little more sense. Developers from a civilized language (like ruby), where you don’t need parenthesis to call a method, are now free to laugh.

For Magento 2 Developers

As a Knockout.js developer, you can live a life that’s mostly ignorant of how observables are implemented. Magento 2 developers don’t have this luxury. The UI Component systems make heavy use of observable properties, and also setup their own subscribers.

The good news is: When you see something like

//...
someProp: ko.observable('default value')
//...

you don’t need to panic. The program is just using someProp to store a value.

The bad news is — that observable may have a number of subscribers. These subscribers may come from a Knockout.js template’s data-bind attributes. They may come from Magento core code setting up their own subscribers. You can view the number of callbacks an observer has via the _subscriptions property

However — you’re at the mercy of your debugger w/r/t to how this information is displayed, and there’s no easy way to tell where a particular subscriber comes from. Also, we’re deep into Knockout.js internals at this point, and relying on this sort of code for anything other than debugging introduces enormous potential for instabilities.

However, when I started researching RequireJS monkey patching and the best way to apply it in Magento 2, I was in for a bit of a surprise. Joe Constant pointed me towards a feature Magento 2 erroneously calls mixins, and all sorts of confusion resulted.

Our end goal today is to teach you a technique for applying a safe method rewrite technique using Magento 2 javascript techniques — one that goes beyond the usual RequireJS tools. To get there though, we’ll need to wade through some very puzzling choices made by Magento’s product and engineering teams.

We’re going to start with a quick programming lesson, continue with some related feature highlights of Magento’s javascript system, and then fall into discussing Magento’s weirdly named mixins system.

Notice no classes inherit from one another. Instead, the programmer indicates that class Cshould get methods from class A and class B. The result is more flexibility, at the expense of some ambiguity about how conflicts between different mixins should work, or what the language syntax should be for specifying mixins.

If you’ve ever used PHP Traits, you’ve used a simplified mixin system. In PHP, you need to define explicit traits, and then can combine those traits in your classes. Traits, by themselves, can’t be instantiated as objects. PHP classes, by themselves, can’t be used as traits.

Contrast this with ruby, which allows one module to completely “include” (or “mix in”) another module’s methods.

You’ll also see the idea of multiple inheritance thrown about in mixin discussions. With multiple inheritance, classes still extend other classes, but you’re allowed to have a single class extend more than one class.

Javascript and Mixins, Sitting in a Tree

Unlike classes, there doesn’t seem to be a consensus on how mixin syntax should work across languages. Some languages have explicit mixins while other languages have de-facto mixins due to the nature of their object system.

Javascript is an example of the later. Javascript doesn’t have any native classes. In javascript, you define methods by attaching functions to objects

var foo = {};
foo.someMethod=function(){
//...
};

Since objects can be easily reflected into, Javascript is a fertile enviornment for developers who want to build systems for creating mixin like objects. One library that offers this sort of functionality (although the word mixin isn’t used) is underscore.js.

Using the extend method in underscore.js, you can have a de-facto mixin-like behavior. Consider the following

However, the uiClassextend method is used for something slightly different. The purpose of the uiClass.extend is to create a new javascript constructor function that’s based on an existing javascript constructor function. Above, NewClass won’t get a bar method, but objects instantiated from it will.

While this feels more like straight inheritance, there might be some folks who would call this a mixin due to the uiClass‘s implementation details.

We’re now going to jump to a completely different topic, but keep all of the above in mind.

Magento 2 RequireJS Mixins

Magento 2’s requirejs-config.js files have a feature that’s labeled as a “mixin”. This feature has (almost) nothing to do with traditional computer science mixins, so we’ll continue to refer to them with the “skeptical quotes”.

Despite all the shade we’re throwing at the feature’s name, it’s actually a very good and important feature. A Magento 2 RequireJS “mixin” allows you to programmatically listen for the initial instantiation of any RequireJS module and manipulate that module before returning it.

If that didn’t make sense, a quick sample module should make things clearer. First, create and enable a blank module with the following pestle commands (or use your own module creating methodology).

If you’re not familiar with these requirejs-config.js files, they allow individual Magento modules to provide configuration values for RequireJS. You can read more about them in our Magento 2 and RequireJS article.

If you are familiar with them, you may be confused by the mixins configuration key. This is not a part of standard RequireJS. This is a special configuration flag Magento introduced to their RequireJS system. Don’t let the word mixins confused you. As we previously mentioned, this has (almost) nothing to do with the programming concept we discussed earlier. It’s just a poorly chosen name.

The mixins property should be an object of key values pairs. The key (Magento_Customer/js/view/customer) is the object whose creation you want to listen for. The value is another object

{
'Pulsestorm_RequireJsRewrite/hook':true
}

The key of this second object is the RequireJS module that’s going to be listening. We named this module hook, but that’s not required. You can use any module name you like here.

These “listener/hook” modules are standard RequireJS modules. They should return a callable object (i.e. a javascript function). This is the function Magento will call after loading a RequireJS module. It has a single parameter (targetModule) above. This variable will be a reference to whatever the spied on RequireJS module (Magento_Customer/js/view/customer in our example) returns.

Whatever this callback function returns will be treated by the rest of the system as the actual module. That’s why Magento_Customer/js/view/customer had our extracrazyPropertyAddedHere property.

Class Rewrites for Javascript

As we’ve mentioned a few times, this is an incredibly powerful feature. One thing you could do with it os replace method implementations on RequireJS modules that return objects

Also, if the module in question returns a uiClass based object? You could use uiClass‘sextend method to return a different class that extended the method, but used uiClass‘s_super() feature to call the parent method.

These are powerful techniques that allow a careful developer, with a small amount of code, to change existing system behavior in exactly the way she wants to. However, like class rewrites in Magento 1, and the class <preference> feature in Magento 2, the above examples are a winner take all situation. While multiple developers can all safely setup their own hooks, they can’t all redefine the same method or function. One person’s modifications will win out over the other person’s.

Fortunately, Magento 2 has a solution for that in the mage/utils/wrapper module.

Wrapping Function Calls

The mage/utils/wrapper module allows for functionality similar to a Magento 2 backend around plugin. Here’s a simple example that should demonstrate what it means to “wrap” a function.

The wrap method accepts two arguments. The first is the original function you want to wrap. The second is the function you want to wrap it with. The originalFunctionparameter will be a reference to the function you’re trying to wrap (example.foo above). The wrap method returns a function that, when called, will call your function. Your function can, if you desire, call the original function.

The point of the wrapper module is to wrap an existing function call with new code without needing to edit the original function. It’s another powerful technique that javascript’s flexible object system enables. Another great thing about wrapping is, multiple people can do it. Try running the following after running the above code.

Here we’ve replaced the definition of someFunction with our wrapped function. This technique also has the advantage of working with RequireJS modules that return functions instead of objects.

Why Call this a Mixin

All this still leaves the question of why Magento calls this feature a mixin. A developer can certainly use this feature to implement mixin like behavior, but the feature itself is more of a listener/hook and has nothing to do with adding methods to objects.

I’m sure, to a non-technical user, all this terminology seems like interchangeable jargon but — words still mean things. When a junior, or even intermediate developer, encounters this feature they’re going to expect some sort of real mixin functionality. They’ll spend hours, possibly days, spinning their wheels trying to make it work until they give up.

When a senior developer encounters this they’re going to wonder why something a simple peer/code-review should have caught made it through engineering, through product, and into a production system. Like so much of Magento 2, it feels like we’re looking at the skeleton of a great new building, but being sold office space.

Regardless, this not really a mixin functionality is powerful, and is the perfect mechanism for changing your system’s behavior. As an extension developer, it’s still a crap shoot as to whether a particular RequireJS module will still be around version to version, but for system integrators who own a particular Magento system (and can adjust customizations over time) not really a mixin customizations will be a boon.

While KnockoutJS bills itself as an MVVM (model, view, view model) framework, PHP developers will find the model portion a little thin. KnockoutJS itself has no native concept of data storage, and like many modern javascript frameworks it was designed to work best with a service only backend. i.e. KnockoutJS’s “Model” is some other framework making AJAX requests to populate view model values.

Something else that might catch you off guard with KnockoutJS is it’s not a “full stack” javascript application framework (and to its credit, doesn’t bill itself as such). KnockoutJS has no opinion on how you include it in your projects, or how you organize your code (although the documentation makes it clear the KnockoutJS team members are fans ofRequireJS).

This presents an interesting challenge for a server side PHP framework like Magento. Not only is there a degree of javascript scaffolding that needs to surround KnockoutJS, but Magento 2 is not a service only framework. While the new API features of Magento 2 are making strides in this direction, Magento 2 is not a service only framework. i.e. The backend framework developers also need to build scaffolding to get business object datainto KnockoutJS.

Today we’re going to dive into Magento 2’s KnockoutJS integration. By the end of this tutorial you’ll understand how Magento 2 applies KnockoutJS bindings as well as how Magento 2 initializes its own custom bindings. You’ll also understand how Magento has modified some core KnockoutJS behavior, why they’ve done this, and the additional possibilities these changes open for your own applications and modules.

This article is part of a longer series covering advanced javascript concepts in Magento 2. While reading the previous articles isn’t 100% mandatory, if you’re struggling with concepts below you may want to review the previous articles before pointing to yourMagento Stack Exchange question in the comments below.

Creating a Magento Module

While this article is javascript heavy, we’ll want our example code to run on a page with Magento’s baseline HTML. This means adding a new module. We’ll do this the same as we did in the first article of this series, and use pestle to create a module with a URL endpoint

These commands should be familiar to anyone who’s worked their way through theMagento 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_knockouttutorial/

and see the renderedapp/code/Pulsestorm/KnockoutTutorial/view/frontend/templates/content.phtmltemplate. Pestle isn’t mandatory here — if you have a preferred way of working with a page in Magento, feel free to use it.

RequireJS Initialization

For tutorial applications, this makes sense. However, if you were to keep all your view model logic, custom bindings, components, etc. in a single chunk of code, KnockoutJS would quickly grow un-manageable.

Instead, Magento’s core team has created the Magento_Ui/js/lib/ko/initializeRequireJS module that, when listed as a dependency, will perform any and all KnockoutJS initialization. You can use this module like this

One interesting thing to note about this RequireJS module is it returns no value. Instead, the sole purpose of listing the RequireJS module as a dependency is to kickoff Magento’s KnockoutJS integration. This might confuse you when you see it in the wild. For example, consider this code from a different Magento RequireJS module.

It’s not clear to me if this is a clever bit of programming, or if its something that violates the spirit of RequireJS. Maybe it’s both.

Regardless, the first time you use this library in your own RequireJS based programs Magento will initialize KnockoutJS. Subsequent inclusions will effectively do nothing, as RequireJS caches your modules the first time you load them.

KnockoutJS Initialization

If we take a look at the source of of the Magento_Ui/js/lib/ko/initialize module

We see a program that’s relatively simple, but that also includes nineteen other modules. Covering what each of these modules does is beyond the scope of this article. Consider the following a highlight reel.

The knockoutjs/knockout module is the actual knockout library file. Theknockoutjs/knockout-repeat,knockoutjs/knockout-fast-foreach, andknockoutjs/knockout-es5 modules are KnockoutJS community extras. None of these are formal RequireJS modules.

The modules that start with ./bind/* are Magento’s custom bindings for KnockoutJS. These are formal RequireJS modules, but do not actually return a module. Instead each script manipulates the global ko object to add bindings to KnockoutJS. We’ll discuss thescope binding below, but if you’re the curious type try investigating the implementation details of the other bindings. It’s a useful exercise. Hopefully Magento gets us official documentation soon.

The two extender modules are Magento core extensions to KnockoutJS’s functionality.

The ./template/engine module returns a customized version of KnockoutJS’s template engine, and is the first customization we’ll dive deeply into.

Magento KnockoutJS Templates

To review, in a stock KnockoutJS system, templates are chunks of pre-written DOM/KnockoutJS code that you can use by referencing their id. These chunks are added to the HTML of the page via script tags, with a type of text/html

This is a powerful feature, but presents a problem for a server side framework — how do you get the right templates rendered on a page? How can you be sure the template will be there without recreating it every-time? The KnockoutJS solution for this is to use the component binding with a library like RequireJS, but this means your templates are tied to a specific view model object.

Magento’s core engineers needed a better way to load KnockoutJS templates — and they did this by replacing the native KnockoutJS template engine with the engine loaded from the Magento_Ui/js/lib/ko/template/engine RequireJS module.

we see Magento makes a new object that prototypically inherits from the native KnockoutJS rendering engine, and then modifies a few methods to add custom behavior. If you’re not up on your javascript internals, this means Magento copies the stock KnockoutJS template system, changes it a bit, and then swaps its new template engine in for the stock one.

The implementation details of these modifications are beyond the scope of this article, but the end result is a KnockoutJS engine that can load templates via URLs from Magento modules.

If that didn’t make sense, an example should clear things up. Add the following to ourcontent.phtml file.

Here we’ve added a KnockoutJS template binding and passed it the stringPulsestorm_KnockoutTutorial/hello. If we reload our page with the above in place, you’ll see an error like the following in your javascript console

Magento has taken our string (Pulsestorm_KnockoutTutorial/hello) and used the first portion (Pulsestorm_KnockoutTutorial) to create a base URL to a view resource, and use the second portion (hello) with a prepended template and an appended .html to finish the URL. If we add a KnockoutJS view to the following file

and reload the page, we’ll see Magento has loaded our template from the above URL, and applied its KnockoutJS bindings.

This feature allows us to avoid littering our HTML page with <script type="text/html"> tags whenever we need a new template, and encourages template reuse between UI and UX features.

No View Model

Coming back to the initialize.js module, after Magento sets the custom template engine, Magento calls KnockoutJS’s applyBindings method. This kicks off rendering the current HTML page as a view. If we take a look at that code, something immediately pops out.

Magento called applyBindingswithout a view model. While this is a legal KnockoutJS call — telling KnockoutJS to apply bindings without data or view model logic seems pretty useless. What is a view without data going to be good for?

In a stock KnockoutJS system, this would be pretty useless. The key to understanding what Magento is doing here is back up in our KnockoutJS initialization

The Magento_Ui/js/core/app RequireJS module is a module that instantiates KnockoutJS view models to use with the scope attribute. Its full implementation is beyond the, um, “scope” of this article, but at a high level Magento will instantiate a new javascript object for each individual RequireJS module configured as a component, and that new object becomes the view model.

If that didn’t make sense, lets run through an example with the above x-magento-init. Magento looks in the components key, and sees one key/object pair.

"customer": {
"component": "Magento_Customer/js/view/customer"
}

So, for the customer key, Magento will run code that’s equivalent to the following.

It’s the registry.get(component, apply); line that fetches the named view model from the view model registry, and then the following code is what actually applies the object as a view model in KnockoutJS

A Component by Any Other Name

By using the same component terminology as KnockoutJS, Magento has opened up a new world of confusion. Even the official documentation seems a little confused on what a component is or isn’t. Such is life on a large software team where the left hand doesn’t know what the right hand is doing — and the rest of the body is freaking out about a third hand growing out of its back.

When discussing these features with colleagues, or asking questions on a Magento forum, it will be important to differentiate between KnockoutJS components, and a Magento components.

Changes in the 2.1 Release Candidate

To wrap up for today, we’re going to talk about a few changes to the above in the Magento 2.1 release candidates. Conceptually, the systems are still the same, but there’s a few changes to the details.

First off, KnockoutJS’s initialization now happens in theMagento_Ui/js/lib/knockout/bootstrap RequireJS module

Finally, the “Magento Javascript Component” returned by Magento_Ui/js/core/app has a changed method signature that includes a merge parameter, and the arguments to thelayout function make it clear layout‘s signature has changed as well.

Beyond being interesting for folks who who are interested in implementation details, these changes point to the fact that Magento’s javascript modules and frameworks are changing rapidly, and unlike the PHP code, Magento’s RequireJS modules don’t have @api markings to indicate stability.

Unless you absolutely need to, it’s probably best to steer clear of dynamically changing the behavior of these core modules, and keep your own javascript as separate as possible.

This is a crash course meant to get a working Magento developer familiar with basic KnockoutJS concepts, with a focus on the features Magento uses. We highly recommend working through the official KnockoutJS tutorials if you plan on building anything of substance with KnockoutJS.

Hello Model, View, View Model

The quickest way to wrap your head around KnockoutJS is a basic example. First, lets create the following HTML page

With the above in place, reload your page and you should see your title and content rendered.

Congratulations! You just created your first KnockoutJS view model and view.

What Just Happened

KnockoutJS bills itself as an “MVVM” system. This stands for Model, View, View Model. Really though, KnockoutJS is better billed as a VVM system, since its agnostic about what sort of model code you use to fetch data. The view is your HTML page. The view model is the javascript object that contains data.

When you call applyBindings, KnockoutJS will scan the entire HTML page for data-bind attributes. When it finds these attributes, it parses the attribute for the binding name and value, and then invokes a set of rules based on the name of the binding.

For example — the binding we invoke above is the text binding. The value we passed to the text binding is title. The set of rules the text binding applies are “use the value passed into the binding to fetch a value from the view model object, and add that value as a text node”. The end result is something that, if written in pure javascript, might look like this

KnockoutJS’s first trick is it gets developers out of the business of directly using javascript to create and update DOM nodes. Instead, developers can write HTML, mark it up withdata-bind attributes, and just assign values to an object. You’re not limited to key/value pairs either. Consider this more sophisticated view model.

Another way of thinking about binding parameters is they’re a temporary, limited javascript scope to access your view model’s values and methods.

Other Bindings

While this example is simple, you can start to see how this basic building block could implement far more complicated view logic. The business of updating the DOM is left to the data-bindings, and the business of updating the model is left to pure non-DOM javascript code.

You can start to see the value of this with other bindings. For example, lets add a theValueproperty in our viewModelConstructor

If you reload the page, you’ll see we’ve bound the value of 1 to our <input/> and <p/>tag. So far our view has nothing new — this is the same sort of binding we were doing previously. However, you’ll notice that we’ve done something different in our view model.

//File: ko-init.jsthis.theValue = ko.observable("1");

Instead of setting theValue to a hard coded value, or a custom function, we’ve set the value to be something KnockoutJS calls an observable. An observable is a special sort of getter and setter.

If you open up your javascript console, and type the following, you’ll see we can fetch the value of the observable by calling it as a function (viewModel is available via the console since we defined it as a global object on the window object)

> viewModel.theValue()
> "1"

We can set a value on the observable by passing in a parameter. Here’s how you’d set, and then get the value of, an observable.

> viewModel.theValue("3")
//...
> viewModel.theValue()
> "3"

However, the real power of an observable is in what happens to the DOM nodes we’ve bound that observable to. Try changing the value of the observer via the console and watch the browser window

As you update the value of the observable, the value of the bound nodes change in real time. Again, as developers, we’re freed from having to worry how the DOM nodes get updated — once we’ve set the value on our model, this value is automatically reflected in the user interface.

While its beyond the scope of this article, you can see how this comes together to form complex javascript applications when our view model includes methods

If you’ve never seen this before it may seem weird/foreign, but many modern javascript frameworks use non-text/javascript<script/> tags as a way to add non-rendered (but DOM accessible) content to a page. A template is just a standard set of HTML nodes with KnockoutJS bindings.

Components

The final binding we’ll at is the component binding. Components are a way to package together a KnockoutJS template, and a KnockoutJS view file. This means you can have a relatively simple view

The register function of the component object expects a name for your component, and then a KnockoutJS component object. A component object is a javascript script object with two properties. The viewModel property expects a view model constructor function, and the template property should be a string with a KnockoutJS template. Once registered, you can use your component by passing the name of the component (as a string) into the binding.

This only scratches the surface of what’s possible with KnockoutJS. The official docs have a pretty good overview of the component binding.

Custom Binding

The final KnockoutJS feature we’ll discuss today is the custom binding feature. KnockoutJS gives javascript developers the ability to create their own bindings. For example, here we’re invoking a custom binding named pulseStormHelloWorld, and passing it the value of the message property of our viewModel.

To add the custom binding to KnockoutJS, all we need to do is add a property to the koobject’s binidngHandlers object. The name of this property is the name of our binding. The handler is a JS object with an update method. KnockoutJS calls the update method whenever a binding is invoked — either during applyBindings, or via an observable.

With the above in place, reload your HTML page and you’ll see the custom binding invoked. This is, of course, a trivial example, but with custom bindings you can make KnockoutJS do anything your programatic mind thinks up.

Wrap Up

KnockoutJS is a powerful, modern, javascript framework. Its semantics, and disregard for traditional HTML concepts, may make some developers shy away at first, but as a tool of organizing and taming DOM complexity in a modern javascript application KnockoutJS has few peers. Our tour here is incomplete, but hopefully it’s enough to get you interested in working through KnockoutJS’s tutorials and documentation for yourself.

All that said, KnockoutJS by itself isn’t enough to build a full javascript application. Next week we’ll take a look at the framework Magento has built around KnockoutJS — both so you can better understand how the core Magento system works, and also so you can incorporate KnockoutJS into your own modules and applications.

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 theMagento 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 renderedapp/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtmltemplate.

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 isPulsestorm_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.phtmltemplate 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 phtmltemplate 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 andincludes 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 ourphtml 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 inPulsestorm_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-initattribute. 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 configparameter.

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 astrict 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 adata-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.