Search code examples
javascriptphpjqueryhtmljquery-ui-multiselect

Jquery multiselect - Togggle hide optgroup issues


I have implemented the jquery multiselect addon and got it working fine. I have a long list of select options and are divided by optgroups. While optgroups organizes my long list but still users still have to scroll for a while to get to the bottom option. I am simply looking for a solution to have the optgroup collapsed by default and un-collapsed when you click on the group.

At the moment when you click on the optgroup it automatically selects all options under it which I would like to prevent and instead replace that with a hide function instead. I know that jquery by default cannot target a select's optgroup but the Jquery Multiple select addon has an event handler that apparently allows you too. If you scroll a bit half way down their site it gives you all the event handlers this addon supports. I was really interested in the optgrouptoggle event:

Fires when an optgroup label is clicked on. This event receives the original event object as the first argument, and a hash of values as the second argument: js $("#multiselect").bind("multiselectoptgrouptoggle", function(event, ui){ /* event: the original event object, most likely "click" ui.inputs: an array of the checkboxes (DOM elements) inside the optgroup ui.label: the text of the optgroup ui.checked: whether or not the checkboxes were checked or unchecked in the toggle (boolean) */ });

I tried implementing a show hide function as follows but I still new with jquery and might be botching this completely. Any help would be appreciated.

http://jsfiddle.net/akhyp/1986/

$("#selected_items").bind("multiselectoptgrouptoggle", function(event, ui){ 
    $(this).children().show();
}, function() {
    $(this).children().hide();
 });

Solution

  • A few problems with this approach, some in your code, some in the plugin's API:

    1. Your demo code references $("#selected_items"), which is nowhere in your markup. Change the selector to $("select") to match your declaration of the multiselect above. Better still, cache the jQuery object in a variable: var $multiselect = $('select');

    2. The docs specify using bind to attach an event listener, but bind is deprecated in recent versions of jQuery. Use on instead.

    3. You're passing two functions to the on/bind method--it only takes one. Instead of using hide() and show(), you can just use jQuery's toggle method.

    4. The multiselect plugin isn't structuring its generated markup semantically, so optgroups and their child option elements are translated into straight-up li elements, with the optgroup and option elements as siblings. That means you can't use children() the way you would hope. However, the API provides you with a way to find the checkboxes that were associated with the optgroup: ui.inputs. From those, you can find each of the parent li elements and hide them. Unfortunately, it doesn't look like the API gives you a way to directly address them, but you can use a code snippet like so:

      var parentLiOfInput = function(input) { return $(input).closest('li'); }; var $listEls = ui.inputs.map(parentLiOfInput); // $listEls is now an array of jQuery objects // Note this isn't the same as a jQuery wrapped set-- // you can't do $listEls.hide(), for example.

    5. Hiding the generated "option" elements will prevent the plugin from working--it uses a jQuery selector to toggle the checkboxes, and that selector relies on the associated elements to be visible.

    That last point is the blocker: Once you hide the checkbox, the plugin will fail on the next optgroup click. Demo of the failing behavior.

    I don't really see any options for you at this point, without directly modifying the code of the plugin.