1

I am trying to extend the default dropdown.js of Magento

1) Created a new JS file at app/design/frontend/<vendor>/<theme-name>/web/js/mage/dropdown.js

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

    $.widget('mage.customdropdownDialog', $.mage.dropdownDialog, {
        _create: function() {
            this._super();
            console.log("Testing...");
        },
    });

    return $.mage.customdropdownDialog;
});

2) Added reference in the requirejs-config.js at app/design/frontend/<vendor>/<theme-name>/requirejs-config.js

var config = {
    map: {
        "*": {
            "dropdownDialog": "js/mage/dropdown"
        }
    }
};

3) Ran php bin/magento setup:upgrade and php bin/magento setup:static-content:deploy

I keep getting the following error whenever I try to click on any dropdown created using the dropdown.js libary.

Uncaught Error: cannot call methods on dropdownDialog prior to initialization; attempted to call method 'close'

I am not sure what I am doing wrong, can anyone please help me with this ?

2
  • update to latest version should fix your problem
    – mrtuvn
    Commented May 16, 2017 at 2:48
  • I am facing the same issue. my code: <script> require([ 'jquery', 'mage/url' ], function ($, mUrl) { $(document).ready(function() { $('[data-block="minicart"]').hover( function() { console.log('shit cart'); // $(this).addClass('active'); // $(this).find('.action.showcart').addClass('active'); $(this).find('[data-role="dropdownDialog"]').dropdownDialog('open'); }, function() { // $(this).removeClass('active'); // $(this).find('.action.showcart').removeClass('active'); $(this).find('[data-role="dropdownDialog"]').dropdownDialog('close'); } ); $('[data-block="minicart"] > a').click(function() { w Commented Jul 4 at 7:40

2 Answers 2

0

I ran into this issue multiple times, and fixed it by the next way:
So, the problem is in line 64 of file lib\web\mage\dropdown.js

 $('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content').dropdownDialog("close");

I think it's needed for closing any other dropdowns before open current dropdown.
The problem is that we can use dropdown methods only with the same jQuery objects they were initialized. But jQuery object $('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content') is new and nothing has been initialized with it.

Possible solution is to use the custom event to properly close the dropdowns without recreating new jQuery objects. For example:

_create: function() {
    this._super();
    this.uiDialog.addClass(this.options.defaultDialogClass);
    var _self = this;

    $(document).on('custom.dropdownOpened', $.proxy(_self.close, _self));

    if (_self.options.triggerTarget) {
        $(_self.options.triggerTarget).on(_self.options.triggerEvent,function(event) {
            event.preventDefault();
            event.stopPropagation();
            if(!_self._isOpen) {
                $(document).trigger('custom.dropdownOpened');
                _self.open();
            }
            else {
                _self.close(event);
            }
        });
   }

    if (_self.options.shadowHinter) {
        _self.hinter = $('<div class="' + _self.options.shadowHinter + '"/>');
        _self.element.append(_self.hinter);
    }
},

So, instead of using "close method" on new object, we trigger a custom event, and handle the widget's method "close" on it. In this case for every dropdown the correct method "close" with the proper scope will be exectuted.

The bad thing about this solution is that we need to override the entire $.mage.dropdownDialog widget and extend $.ui.dialog widget instead.

Hope, it helps.

0

This happens because of this line in the original widget:

$('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content').dropdownDialog('close');

This is calling the dropdownDialog widget which we have overridden. In your case you've overridden with customdropdownDialog which is the widget that will get instantiated on the elements. In other words, the error is right: dropdownDialog has not been intialiazed, because customdropdownDialog has been intialized instead.

So the call to interact with that instatiated widget should now be:

$('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content').customdropdownDialog('close');

In order to deal with this, you'll need to take control of the event listener that powers the interaction with the dropdown widget. Based on the code you posted, it would be something like this:

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

    $.widget('mage.customdropdownDialog', $.mage.dropdownDialog, {
        _create: function() {
            this._super();
            console.log("Testing...");

            if (_self.options.triggerTarget) {
                $(_self.options.triggerTarget).off(_self.options.triggerEvent); // remove original event, created by parent ($.mage.dropdownDialog)

                // recreate the event listener, changing only the call to other dropdowns
                $(_self.options.triggerTarget).on(_self.options.triggerEvent, function(event) {
                    event.preventDefault();
                    event.stopPropagation();

                    if (!_self._isOpen) {
                        $('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content').customdropdownDialog('close');
                        _self.open();
                    } else {
                        _self.close(event);
                    }
                });
            }
        }
    });

    return $.mage.customdropdownDialog;

});

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.