'Not able to override collapsible.js in magento 2

I'm working on Magento EE 2.1.1 and I need to extend activate method functionality which located in lib/web/mage/collapsible.js . but I can't find the right way with Magento documentation and googling, so here are my tries and what was the issue for each:

  1. try 1:

    • created following file:

namespace_module_dir/view/frontend/web/js/collapsible-mixin.js


define([
    'jquery'
], function ($) {
    'use strict';
    var mixin = {
        activate: function () {
            if (!this.options.disabled) {
                if (this.options.animate) {
                    this._animate(showProps);
                } else {

// my custom code goes here ...
                    this.content.show();
                }
                this._open();
            }
        }
    };

    return function (target) {
         return target.extend(mixin);
    };

});

  • created requirejs-config file

namespace_module_dir/view/frontend/requirejs-config.js


    var config = {
    config: {
        mixins: {
            'mage/collapsible': {
                '<namespace_module>/js/collapsible-mixin': true
            }
        }
    }
};

issue is:

uncaught exception ...

  1. try 2:
    • created requirejs-config file

namespace_module_dir/view/frontend/requirejs-config.js


    var config = {
    map: {
        '*': {
            collapsible: '<namespace_module>/js/collapsible-map'
        }
    }
};

issue is: regardless what is the content of collapsible-map.js, it's not getting loaded (collapsible-map.js file is created) even thought I can see my requirejs-config.js content in the auto generated requirejs-config.js file by magento and the defalut magento collapsible.js file is loaded.

  1. try 3:
    • created following file:

namespace_module_dir/view/frontend/web/js/collapsible-map.js


    define([
    'jquery',
    'jquery/ui',
    'mage/collapsible'
], function ($) {
    "use strict";
    $.widget('<namespace_module>.collapsible', $.mage.collapsible, {
        activate: function () {
            if (!this.options.disabled) {
                if (this.options.animate) {
                    this._animate(showProps);
                } else {

                    // custome code goes here ...

                    this.content.show();
                }
                this._open();
            }
        }
    });
    return $.ctv.collapsible;
});
  • created requirejs-config file

namespace_module_dir/view/frontend/requirejs-config.js


var config = {
        map: {
            '*': {
                'mage/collapsible': '<namespace_module>/js/collapsible-mixin'
            }
        }
    };

issue is:

uncaught exception ...

where with debugging found that typeof $.mage.collapsible = undefined

so please tell me what am I missing, and what's the best way to follow?? :(

thanks inadvance ...



Solution 1:[1]

To override collapsible.js this worked for me:

  1. Copy Original FROM: lib/web/mage/collapsible.js TO: app/design/frontend/VENDOR/THEME/web/js/collapsible-custom.js

NOTE: The copied version of collapsible.js has been renamed to collapsible-custom.js

  1. Add a requirejs-config file in our theme directory and map the original collapsible.js file to our new custom one. app/design/frontend/VENDOR/THEME/requirejs-config.js

    var config = {
        "map": {
            "*": {
                "mage/collapsible": "js/collapsible-custom"
            }
        }
    };
    
  2. Refresh your page and check the inspector to see if our collapsible-custom.js has loaded.

enter image description here

Solution 2:[2]

mage.collapsible is a JqueryUi widget. For more, see the documentation of JqueryUi. I'd rather do it like below, instead of copy JS file from core Magento 2 code into theme and modify the function, or just replace the widget with mine but add only one function in it.

This should work, in [my theme dir]/web/mage/my-collapsible-mixin.js:

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

    return function(target) {
        $.widget("mage.myCollapsible", target, {
            activate: function () {
               if (!this.options.disabled) {
                   if (this.options.animate) {
                       this._animate(showProps);
                   } else {
                      // custom code goes here ...
                      this.content.show();
                   }
                   this._open();
               }

               // Or:
               // this._super();
               // if (!this.options.disabled) { .. custom code .. }
            }
        });
    };
});

Additional suggestion & not tested: replace above variable 'this' with 'target'.

And in require-config.js from [my theme dir]:

var config = {
    config: {
        mixins: {
            'mage/collapsible': {
                'mage/my-collapsible-mixin': true
            }
        }
    }
};

Solution 3:[3]

To fix your try 3, change the 'mage/collapsible' to just 'collapsible' in the map:

var config = { map: { '*': { 'collapsible': '<namespace_module>/js/collapsible-map' } } };

I suppose the bug was caused by the circular reference: collapsible-map.js was referencing mage/collapsible while mage/collapsible was mapped again to collapsible-map. The alias 'collapsible' is used for mage/collapsible, it is configured in Theme\view\frontend\requirejs-config.js. So you can re-map this alias to your own file, while referencing the real mage/collapsible within your file.

The try 1 and 2 were wrong because mixins can be only applied to UI Components. Which means the component must be extendend from uiClass, uiElement, uiCollection or any other ui component. The collapsible.js is just jQuery widget.

Some useful links:

Exteding components or widgets (which are not the same!): http://devdocs.magento.com/guides/v2.1/javascript-dev-guide/javascript/custom_js.html

jQuery widgets: https://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/

Solution 4:[4]

Your requirejs-config.js is fine. For the mixin, you can do something like that :

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

    return function(widget) {
        $.widget('mage.collapsible', widget, {
            activate: function () {
               if (!this.options.disabled) {
                   if (this.options.animate) {
                       this._animate(showProps);
                   } else {
                      // custom code goes here ...
                      this.content.show();
                   }
                   this._open();
               }
            }
        });

        return $.mage.collapsible;
    };
});

Solution 5:[5]

Here is the workaround which might help you

First of all create require-config.js file under app/design/frontend/Vendor/Themename/Vendor_Modulename/requirejs-config.js

requirejs-config.js

var config = {
    config: {
        mixins: {
            'mage/collapsible': {
                'Vendor_Modulename/js/lib/mage/collapsible-mixin': true
            }
        }
    }
};

Then make a mixin file under app/design/frontend/Vendor/Themename/Vendor_Modulename/web/js/lib/mage/collapsible-mixin.js

collapsible-mixin.js

define([
    'jquery'
], function ($) {
   'use strict';
    return function(originalWidget) {
        $.widget('mage.collapsible', $.mage.collapsible, {
            _scrollToTopIfNotVisible: function () {
                console.log('Mixin Loaded');
            }
        });
        return $.mage.collapsible;
    };
});

After creating both file run below commands

  1. bin/magento setup:upgrade
  2. bin/magento setup:di:compile
  3. bin/magento cache:flush

After running above commands still mixin file is not loading then flush your browsers cache

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 toti08
Solution 2 Pang
Solution 3 ma1ao
Solution 4 Balix
Solution 5 Nirav Joshi