Magento 2: Calling and Initializing JavaScript

In the last post I showed you how to add a JavaScript file globally across your Magento 2 store. Today I’ll show you two more methods of loading, imperative and declarative. These methods allow you to only load the relevant JavaScript when required, as apposed to one global JavaScript file.

Imperative notation

The simplest method of the two, imperative notation allows using raw JavaScript code on the pages. The notation using the <script> tag, without the type="text/x-magento-init attribute, is the imperative notation.

<script>
    require([
        'jquery'
    ], function($) {
        'use strict';

        $(function() { // document.ready shorthand
            console.log('loaded');
        });
    });
</script>

Declarative notation

This method is more complex but with it comes better flexibility allowing you to re-use the component with different configurations. Using the declarative notation to insert a JS component allows preparing all the configuration on the backend side and outputting it to the page source.

In Magento 2 there are two ways of declarative notation:

1. using the <script type="text/x-magento-init" /> tag
2. using the data-mage-init attribute

With the declarative notation the JavaScript functionality is separated from the configuration, unlike the imperative notation where we simply added it on the pages.

With this in mind before we go any further create a new file in your theme directory:

app/design/frontend/<VendorName>/<ThemeName>/Magento_Theme/web/js/example.js

Now add the following contents:

define([
    'jquery'
], function($) {
    'use strict';

    var exampleComponent = function(config, element) {
        console.log(config);
        console.log(element);
    };

    return exampleComponent;
});

For now we are returning a function that logs parameters that have been passed through. We will return to this file later on.

Now we have the file setup we have the following methods to use it.

Using the script tag

Component initialised on the element defined by selector:

<div class="selector">
    <p>Example JavaScript Component</p>
</div>

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

binding-element

Component initialised without binding to an element:

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

no-binding-element

Notice in the console the difference between having a defined selector and initialising without binding to an element, when not using a selector it will return false.

Using the data-mage-init tag

Use the data-mage-init attribute to insert a JS component in a certain HTML element. When inserted in a certain element, the script is called only for this particular element. It is not automatically called for other elements of this type on the page.

<div class="selector" data-mage-init='{
    "Magento_Theme/js/example": {
        "optionOne": "valueOne",
        "optionTwo": "valueTwo"
    }
}'>
    <p>Example JavaScript Component</p>
</div>

The declarative notation provides a great way to pass configuration from the backend side, for illustrative purposes you could pass a url to the JavaScript component:

<script type="text/x-magento-init">
    {
        ".selector": {
            "Magento_Theme/js/example": {
                "accountUrl": "<?php echo $block->getUrl('customer/account'); ?>"
            }
        }
    }
</script>

Improving The Path

We can improve the code by mapping the path Magento_Theme/js/example to a name, so instead of typing out the path each time you want to use the JavaScript component, you can simply reference the mapped name.

To do this you need to update your RequireJS configuration. If you haven’t already done so create a new file under your theme directory called requirejs-config.js:

app/design/frontend/<VendorName>/<ThemeName>/requirejs-config.js

Now add the following contents:

var config = {
    map: {
        '*': {
            'exampleComponent': 'Magento_Theme/js/example'
        }
    }
};

From here we can use the name exampleComponent instead when initialising the JavaScript:

<script type="text/x-magento-init">
    {
        ".selector": {
            "exampleComponent": {
                "optionOne": "valueOne",
                "optionTwo": "valueTwo"
            }
        }
    }
</script>

As you can see each method is useful for different situations and by using these methods over time you’ll become accustomed to which ones to use in each situation.