0

I've created custom widget by extending jQuery UI's Menu. It's basically needed to work with <select> HTML element like ui.selectmenu does, but display options in submenus:

$.widget("market.myMenu",$.ui.menu, {
// ...
_attachEvents: function(){
    var self = this;
    // menu is initially hidden
    self.menuWrapper.hide();
    self.button.on('click', function(){
        if (self.originalSelect.is(':disabled')) {
            self.disable();
        } else {                
            self.menuWrapper.toggle();
        }
        return false;
    });

    $(document).on('click', function(){
        self.menuWrapper.hide();
    });             
},
//...
  }
}

The problem arise when this widget attached to multiple elements like:

someSelect.myMenu();
//...
anotherSelect.myMenu();

The problem is listed in the title and you can see it in _attachEvents() method:

  1. when user clicks on someSelect it opens as should
  2. then user clicks on anotherSelect it also opens
  3. someSelect after step 2 should be closed, but it's not.

So how to check for such a case and fix this issue ?

EDIT:

  1. this.originalSelect is <select> HTML element
  2. this.button is div element. on which selected option text is displayed (basically same thing as ui.selectmenu does);
marknorkin
  • 3,904
  • 10
  • 46
  • 82

2 Answers2

1

You can use a class to keep track of the state of your menus and use it to target instances that are opened. Something like this for example:

_attachEvents: function(){
    var self = this;
    // menu is initially hidden
    self.menuWrapper.hide();
    self.button.on('click', function(){
        if (self.originalSelect.is(':disabled')) {
            self.disable();
        } else {
            // before you open a menu, you close the opened ones
            $('menu-opened').each(function(){
                $(this).myMenu('instance').hideWrapper();
            });
            self.menuWrapper.toggleClass('menu-opened');                
            self.menuWrapper.toggle();
        }
        return false;
    });

    $(document).on('click', function(){
        self.menuWrapper.hide();
    });             
},

hideWrapper: function(){
    var self = this;
    self.menuWrapper.hide();
    self.menuWrapper.removeClass('menu-opened');
}
Julien Grégoire
  • 16,864
  • 4
  • 32
  • 57
  • I've tried your solution, and it doesn't work as should. The `instance` method silently fails, also would you please fix a typo on selector `.menu-opened`. But anyway I took your idea about marking wrapper with some css class, that is why I accept your answer. Thank you! – marknorkin Oct 29 '15 at 08:42
0

I've found solution. It's based upon Julien Grégoire proposal to use css marker class.

What I'm doing is adding class ui-mymenu-wrap to self.menuWrapper element. So all widgets have those identifier. The next thing I do is after clicking on one widget I'm closing all others menus and then open/close widget on which click was made.

_attachEvents: function(){
    var self = this;
    // menu is initially hidden
    self.menuWrapper.hide();
    self.button.on('click', function(event){
        if (self.originalSelect.is(':disabled')) {
            self.disable();
        } else {
            // hide all opened menus
            $('.ui-mymenu-wrap').not(self.menuWrapper).hide();
            self.menuWrapper.toggle();                  
        }
        return false;
    });

    $(document).on('click', function(){
        self.menuWrapper.hide();
    });             
},
marknorkin
  • 3,904
  • 10
  • 46
  • 82