6

A plugin as far as I read is created for intercepting a PHP function call and running code before, after, or around that function call. Is there a way how to accomplish that in js file?

How can i intercept Magento 2 module js file function call with another function that is located in another module?

Example: js generates an array and i want to add additional element into that array with another module, before it gets processed by another js function. Similar to what is done in magento checkout customization tutorials but only using js file(s) (adding layout elements dynamically).

PS: Can it be done and if not then why? What might be cons? Sorry if that is against any js patterns or best practices?

1 Answer 1

13

You do this with using a requirejs mixin and the mage/utils/wrapper js module.

Heres a demonstration of how the wrapper module functions:

var wrapper = require('mage/utils/wrapper');

function multiply(a, b) {
    return a * b;
}

var wrapped1 = wrapper.wrap(multiply, function (_super) {
    var result = _super();
    return result + 1;
});

var wrapped2 = wrapper.wrap(multiply, function (_super, a, b) {
    a += 1;
    return _super(a, b);
});

multiply(2, 2); // result is 4
wrapped1(2, 2); // result is 5
wrapped2(2, 2); // result is 6

In this example, wrapped1 works like an 'after' plugin, and wrapped2 works like a 'before' plugin. You can combine the two to get an 'around' plugin.

For a real world example, here's how to create a plugin for the collectData method of Magento/Ui/view/base/web/js/form/from.js. We need to use a requirejs 'mixin' to do this.

In your module, create the file Your/Module/view/base/web/requirejs-config.js:

var config = {
    'config': {
        'mixins': {
            'Magento_Ui/js/form/form': {
                'Your_Module/js/plugin': true
            }
        }
    }
};

Now make the file Your/Module/view/base/web/js/plugin.js:

define([
    'mage/utils/wrapper'
], function (wrapper) {
    'use strict';

    return function (Form) {

        var newMethod = wrapper.wrap(Form.collectData, function (_super, items) {
            items = before(items); // the 'before' plugin
            var result = _super(items); // call original method
            return after(result); // the 'after' plugin
        });

        Form.collectData = newMethod; // replace original method with wrapped version

        return Form;
    }
});

You can read more about mixins and wrapper here: http://alanstorm.com/the-curious-case-of-magento-2-mixins/

3
  • Doesn't seem to work for me. The only way I can get the mixin to intercept the original method is using Form.extend({... otherwise it simply ignores everything else using the logic provided above. Commented Feb 13, 2018 at 23:48
  • You're correct, since Form is a uiClass constructor, we should extend it. The above method should be used for modules that export an object. Commented Feb 14, 2018 at 3:26
  • We can use wrapper.wrapSuper to extend a js object, refer: devdocs.magento.com/guides/v2.3/javascript-dev-guide/javascript/…
    – ANKIT
    Commented Jan 15, 2020 at 7:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.