To give your online store a modern, smart look without globally altering the current design, you can include to it dynamic, changing elements. The best solution for adding such elements in Magento 2 is JavaScript, and how to work with it we already described in the previous article.
In today’s blog post we will go over the jQuery, jQuery UI widgets and requireJS – the important tools the developer needs to master if they want to work productively with JavaScript in Magento 2.
Table of Contents:
What are jQuery and jQuery UI widgets?
How can jQuery UI Widget methods be instantiated?
How can you add new methods to a jQuery UI Widget?
How can a jQuery UI Widget method be wrapped with custom logic?
How do you load a file with require.js and define a require.js module?
How are require.js module dependencies specified?
How are module aliases configured in requirejs-config.js?
How do you debug which file a requireJS alias refers to?
What are jQuery and jQuery UI widgets?
To simplify the creation of various elements like drop-down lists, accordions, buttons, datepickers, etc., Magento implements jquery and jquery UI libraries.
If you compare jquery and pure js, then the jquery code is significantly shorter and simpler, but at the same time has a far larger load on browser performance.
jquery UI is a library extension that provides a set of out-of-the-box widgets for projects.
How to use Magento core jQuery widgets?
Magento uses jquery UI widgets to save development time, so the most commonly used elements in projects are already available for use with no need for configuration.
Practically in any project you have to make a FAQ page, or tabs with product descriptions, and date picker or slider will be the widgets that you will most likely use in your theme for that purpose.
How can jQuery UI Widget methods be instantiated?
Using the accordion as an example ($ (“# element”). accordion ();) I will show you how the call process is performed. It can be done in different ways.
Method #1: In the template using the script.
1 2 3 4 5 6 7 |
<script> require([ 'jquery', 'accordion'], function ($) { $("#element").accordion(); }); </script> |
Method #2: In the template using data-mage-init.
1 2 3 4 5 6 7 |
<div id="element" data-mage-init='{"collapsible":{"openedState": "active", "collapsible": true, "active": true, "collateral": { "openedState": "filter-active", "element": "body" } }}'> <div data-role="collapsible"> <div data-role="trigger"> <span>Title 1</span> </div> </div> <div data-role="content">Content 1</div> |
Method #3: In the script file, using a selector, or by calling a function.
1 2 3 4 5 |
require([ 'jquery', 'accordion'], function ($) { $("#element").accordion(); }); |
Method #4: Using <script type=”text/x-magento-init” />.
1 2 3 4 5 6 7 8 |
<script type="text/x-magento-init"> { "#element": { // your selector that uses the widget "accordion": // variables are listed here, for example <?php echo $block->getNavigationAccordionConfig(); ?> } } <script> |
How can you call jQuery UI Widget methods?
It is executed with the following code:
1 |
$ ('# element'). accordion ("someAction"); |
Call the widget and the function we want via the method.
How can you add new methods to a jQuery UI Widget?
To add new methods to a jQuery UI Widget, we either add an existing widget (using mixin), or create a custom component ourselves. The first option is preferable when we aim to only expand the existing code. Otherwise, when you work from scratch, it is better to stick to the second one.
Let’s consider the first path:
app/code/Vendor/Module/view/frontend/requirejs-config.js
1 2 3 4 5 6 7 8 9 |
var config = { "config": { "mixins": { "mage/tabs": { 'Vendor_Module/js/accordion-mixin': true } } } }; |
app/code/Vendor/Module/view/frontend/web/js/accordion-mixin.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
define([ 'jquery' ], function($) { return function (original) { $.widget('mage.accordion', original, { activate: function() { // your code here return this._super(); } } ); return $['mage']['accordion']; } }); |
How can a jQuery UI Widget method be wrapped with custom logic?
The second option is to introduce a custom component:
app/code/Vendor/Module/view/frontend/web/js/custom-accordion.js
1 2 3 4 5 6 7 8 9 10 11 |
define([ 'jquery', 'jquery/ui', 'mage/accordion' ], function($) { $.widget('vendor.customAccordion', $.mage.accordion, { someAction: function(element) { // your code here } }); }); |
Then we add to the template the following:
app/code/Vendor/Module/view/frontend/templates/test.phtml
1 2 3 4 5 6 7 8 9 10 |
<div id="element"></div> <script> require([ 'jquery', 'Vendor_Module/js/custom-accordion'], function ($) { $("#element").customAccordion(); $("#element").customAccordion("someAction"); // Calling the vidget function the way we described before }); </script> |
How do you load a file with require.js and define a require.js module?
Magento 2 introduced a number of innovations in the use of JavaScript, and one of them is requireJS (javascript file loader).
In order to add the Js file to your magento 2 custom module, you need to add the requirejs-config.js file to your module at the path app / code / <Company> / <modulename> / view / frontend.
1 2 3 4 5 6 7 |
var config = { map: { '*': { belvgmodule: 'Company_modulename/js/belvgrequirejs', } } }; |
For example, in this case the map property contains an object with the key that is an alias to file and value that is real path to file.
“*” Is used to determine that you are using a new module in require js; if you want to add a file to the existing module, you will need to specify the name of the module instead of “*”.
No file extension is required, because the system accepts js as the default type.
The united configuration will be loaded to the page immediately after require.js and will be used by the require () and define () functions.
Let me show you how to define a require js module using a helper / belvg module as an example. To use the module, we need to add the following code to the JS file (main.js for example):
1 2 3 4 |
requirejs(['helper/belvg'], function(helper_belvg) { var message = helper_belvg.getMessage(); alert(message); }); |
We specify the modules as an array that we want to load and pass this array as the first argument to the require.js function call. RequireJS then passes the object that exports the helper / belvg module to our main function as the first parameter of helper_belvg.
Then we need to define a helper / belvg module. To define a module, turn the module name into a file path, and add the following contents (scripts / helper / belvg.js):
1 2 3 4 5 6 7 8 |
define([], function(){ var x = {}; x.getMessage = function() { return 'Some message'; } return x; }); |
How are require.js module dependencies specified?
To build a dependency on a third-party plugin, specify [shim] in the following configuration files:
requirejs-config.js
1 2 3 4 5 |
var config = { "shim": { "3-rd-party-plugin": ["jquery"] } }; |
<third-party-plugin>.js
1 2 3 4 |
!(function($){ // plugin code // where $ == jQuery })(jQuery); |
How are module aliases configured in requirejs-config.js?
In our example, the name of the module RequireJS was tied to the location of this module on the disk. In other words, the helper / belvg module will always be located in the helper / belvg.js path.
RequireJS allows you to change this through configuration. For example, if you want your helper / belvg module to be called hello, you would run the following configuration code before running your program:
1 2 3 4 5 |
require.config({ paths: { "hello": "helper/belvg" }, }); |
The paths configuration key is the place where we can rename the modules. The paths object key is the name you want to assign (hello), and the value is the actual module name (helper / belvg).
Therefore, we can work with the module like this:
1 2 3 |
requirejs(['hello'], function(hello) { alert("Some message"); }); |
How do you regenerate the compiled requirejs-config.js file after changes?
Remove static content and execute:
php bin / magento cache: clean
How do you debug which file a requireJS alias refers to?
To track which file corresponds to the renamed module, you need to open the requirejs-config.js file:
1 2 3 4 5 6 7 |
var config = { map: { '*': { addToCart: 'Magento_Module/js/module' } } }; |
You can find the key map in the file which there are aliases parameters of the module and its path.
Demonstrate that you understand how to create and configure Magento JavaScript mixins.
Magento 2 comes with a variety of functional capabilities, and when it comes to redefining the javascript component or extending the javascript component in Magento 2, you need to use mixins.
Mixins are JavaScript files located in the web / js directory. A mixin file can be embedded in several directories if these directories are in web / js.
The example of creating a mixin for custom product samples:
Step 1. Create app/code/VendorName/ModuleName/view/frontend/requirejs-config.js
1 2 3 4 5 6 7 8 9 |
var config = { config: { mixins: { 'Magento_Swatches/js/swatch-renderer': { 'VendorName_ModuleName/js/swatch-renderer-mixin': true } } } }; |
Step 2. Create app/code/VendorName/ModuleName/view/frontend/web/js/swatch-renderer-mixin.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
define(['jquery'], function ($) { 'use strict'; return function (SwatchRenderer) { $.widget('VendorName.SwatchRenderer', $['mage']['SwatchRenderer'], { _init: function () { console.log('getProductSwatchRenderer'); this._super(); } }); return $['mage']['SwatchRenderer']; }; }); |
The example of mixin for Magento_Checkout payment information:
1. Create app/code/VendorName/ModuleName/view/frontend/requirejs-config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ var config = { config: { mixins: { 'Magento_Checkout/js/action/set-payment-information': { 'Magento_CheckoutAgreements/js/model/set-payment-information-mixin': true } } } }; |
2. Create app/code/VendorName/ModuleName/view/frontend/web/js/set-payment-information-mixin.js (example: /app/code/Magento/CheckoutAgreements/view/frontend/web/js/model/set-payment-information-mixin.js).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global alert*/ define([ 'jquery', 'mage/utils/wrapper', 'Magento_CheckoutAgreements/js/model/agreements-assigner' ], function ($, wrapper, agreementsAssigner) { 'use strict'; return function (placeOrderAction) { /** Override place-order-mixin for set-payment-information action as they differs only by method signature */ return wrapper.wrap(placeOrderAction, function (originalAction, messageContainer, paymentData) { agreementsAssigner(paymentData); return originalAction(messageContainer, paymentData); }); }; }); |
Summary
JavaScript is a very useful technology for ecommerce developer, yet it has one flaw – JavaScript elements tend to slow down the pages loading, worsening your store performance. Defer JS for Magento 2 is a great tool to optimize your webstore – it moves JavaScript to the bottom of the page, defering its parсing and loading. This way, your customers will experience the pleasure of comfortable and fast online shopping.
Hi, thanks for the question. It is impossible to pass variables through requirejs, only the paths to the necessary widgets and custom widgets are written in this file.
what about passing variables to a widget via the requirejs file?