Chosen: Make the optgroup labels clickable

Created on 26 Oct 2011  ·  38Comments  ·  Source: harvesthq/chosen

When using a select with optgroups, having all the items in a group added to the selection when the group label is clicked would be a very handy feature. It would make selecting a group minus one item very easy too.
For instance, I have a filter form with countries grouped by zone. For the moment, if someone wants to select a group minus one item, he must select all items one by one. With this feature, he would simply click on the group and remove the country he does not want.

Feature Request

Most helpful comment

@Fr3nzzy: if I may, standard html-select doesn't allow to search either... yet it's very convenient, and that's why Chosen is great -- it improves the standard select. I guess we could apply the same reasoning here.

@greg0ire: +1, i'm also looking for this :o)

All 38 comments

This will be useful, but standart html-select does not allow it.

@Fr3nzzy: yes, but if it were optional, this wouldn't be a problem, would it?

@Fr3nzzy: if I may, standard html-select doesn't allow to search either... yet it's very convenient, and that's why Chosen is great -- it improves the standard select. I guess we could apply the same reasoning here.

@greg0ire: +1, i'm also looking for this :o)

@pilap82 However, select supports finding an item via typing its name.

fair enough :)

Maybe not the best place for a patch, but I hope it could help:

$( '.chzn-results .group-result' ).each( function () {
    var self      = $( this )
        , options = $( '~li', self )
        , next    = options.filter( '.group-result' ).get( 0 )
    ;
    self.data( 'chzn-options', options.slice( 0, options.index( next ) ) );
} )
.click( function () { 
    $( this ).data( 'chzn-options' ).mouseup()
 } )
.hover( function () { 
    $( this ).data( 'chzn-options' ).addClass( 'highlighted' );
 }, function () { 
    $( this ).data( 'chzn-options' ).removeClass( 'highlighted' );
 } )
.css( { cursor: 'pointer' } );

This is a great idea. I'm willing to submit a pull request if the core team would be open to merge it. What do you think @pfiller?

sample of batch select with chosen:

http://vafada.github.com/chosen-dojo/

Well done!

I'd like to see this get added to Chosen, but event listening should be added in a less intensive way. @adriengibrat's solution applies a listener to each group which doesn't perform as well if there are hundreds of groups. We already have a click event on the search results div that can be tested against option groups. If the option is set, css should be used to change the background color.

+1. I was thinking that when the optgroup is selected, it would (optionally) disable/hide all its children.

+1 for this feature

@pfiller any update on this or the search_improvements branch? Would love to see it merged to master.

I need selectable groups too. I originally tried to change the code – then was inspired by the oft-offered answer to "skip the optgroup and add spaces to indent the sub-items". That looked awful but since Chosen is nicely styled by CSS… how about use a non-optgroup select and use a class on each option to make it look like a grouped display?

You can see a basic version in this fiddle: http://jsfiddle.net/slothbear/9xqpF/

I didn't spend a lot of time of the style, but you'll get the idea. This provides two features I need – selectable optgroups, and searchable optgroups. All without optgroups.

I'm close to moving forward with this technique on my project, but I'm looking for feedback. It appears to work. Can you think of a better way? Or any gotchas?

_Just realized I should probably mention – that fiddle is using the Koenpunt fork of Chosen, to enable option adding. But I don't think that affects this example._

_I'm also looking for guidance. I know this technique is probably pretty far afield of the Chosen Philosophy to stick close to the select features – but if an option is appropriate for this feature, I'd be happy to do the work._

+1 for this feature, I found chosen while looking for a way to support this

(I was looking for being able to select a group title OR select a group item) as per Slothbear's above

Edit: In the end I emulated this doing the following.
Note the classes, I also added .clickable to the css which sets the cursor to a pointer.

<select name="category" data-placeholder="Choose a category..." class="chosen-select">
    <option value="group-1 class="group-result clickable">Group Title</option>
    <option value="1" class="group-option">Item Name</option>
    <option value="2" class="group-option">Item Name</option>
</select>

Here is my solution. Although, it's specific for my needs, one can easily tweak with it and change it to his needs.

Example:
cars
-car1
-car2
-car3
plane
-plane1
-plane2

What I did is to create a new option in the beginning off all groups, that way, the 'All' options will come right after groups:
cars
-All cars
-car1
-car2
-car3
people
-All people
-person1
-person2

In 'results_option_build' , pass the 'All' option to 'result_add_group' as second parameter when data is a group, and skip the 'All' option in the next iteration:

if (data.group) {
content += this.result_add_group(data, _ref[++_i])

Now, lets go to 'result_add_group' and replace the group with the option we passed, but keep the style of group:
result_add_group = function(group, option) {
.
.
return "

  • " + group.search_text + "
  • ";

    That's it.. If you want, change the cursor to pointer in css.

    None of these seem to take the search capability into account. By default in chosen, if you search for an option, it will show the group label too. This method does not, if i have several groups and they have identical options, this will make it so I just end up with a list of visually identical items.

    Would be very interesting to be integrated as an option in the library, as much would facilitate the management of multiple select. Do you have referred to squeeze in some version? a greeting

    I have this implemented just using the javascript, its a temporary fix. I don't use it for multiple selections though, I use it for custom grouping. I ended up making the groups be options but look like groups, and gave the 'groups' keywords that when you do a search for the sub-option, the group will show like it would normally in chosen.js http://stackoverflow.com/q/22336052/744228

    I added this into my local copy of chosen because it was a requirement for my project. It was fairly easy in the end.

    In the set_default_values function I put this.group_selectable = this.options.group_selectable != null ? this.options.group_selectable === true : false; at the end.

    Then in result_add_group I changed the classes assigned to the group to be

    if (this.group_selectable) {
            group_el.className = "active-result group-result";
          } else {
            group_el.className = "group-result";
          }
    group_el.setAttribute("data-group-array-index", group.array_index);
    

    And last but not least in result_select a bit of a hack and added

    if (high[0].getAttribute("data-group-array-index")) {
              var that = this;
              high.nextUntil('.group-result').each(function(index, element) {
                that.result_highlight = $(element);
                that.result_select(evt);
              });
            }
    

    just before
    item = this.results_data[high[0].getAttribute("data-option-array-index")];

    See full code at https://gist.github.com/ruhley/9944574

    https://gist.github.com/ruhley/9944574#file-chosen-jquery-js-L1005

    var itm = that.results_data[element.getAttribute("data-option-array-index")];
    if(itm && !itm.selected){
        that.result_highlight = $(element);
        that.result_select(evt);
    }
    

    A bit late to the party, but: +1 for this feature!

    @ruhley +1 for your solution, works like a charm!
    Just a small detail that's in the full code page but not in the code segment : there's an
    else{
    missing at the end.

    Hi,
    Thank you @ruhley for your code.
    But with you modifications, the group is not disabled after being clicked and can be reselected.

    Here are my improvements (based on chosen 1.4.2):

    • After line 158, in "set_default_values" function, add :
    this.group_selectable = this.options.group_selectable != null ? this.options.group_selectable === true : false;
    

    _Addition of the parameter_

    • Change line 222, in "results_option_build" function, with:
    content += this.result_add_group(data, _ref.slice(_i+1, _i+data.children+1));
    

    _Give the childrens to the "result_add_group" function._

    • Change line 272, redifinition of the "result_add_group" function, with:
    AbstractChosen.prototype.result_add_group = function(group, childrens) {
    

    _In order to receive the childrens_

    • After line 285 (group_el = document.createElement("li");), in "result_add_group" function, add:
    if (this.group_selectable) {
      var all = true;
      $.each(childrens, function(index, element) {
        if(!element.selected){
          all = false;
        }
      });
      if(!all) {
        classes.push("active-result");
      } else {
        classes.push("result-selected");
      }
    }
    group_el.setAttribute("data-group-array-index", group.array_index);
    

    _This make the group clickable if at least one child is not selected. (this part is improvable because of the "all" variable)._

    • After line 1052 (high.addClass("result-selected");), in "result_select" function, add :
    if (high[0].getAttribute("data-group-array-index")) {
      var that = this;
      high.nextUntil('.group-result').each(function(index, element) {
        if($(element).hasClass('active-result')) {
          that.result_highlight = $(element);
          that.result_select(evt); 
        }
      });
    } else {
    

    _This only add unselected childrens._

    • After Line 1083, in "result_select" function:
    }
    

    _Need to close the condition of a clicked group._

    Don't forget to indent correctly that piece of code ;)

    Here is a full version of my file : https://gist.github.com/GuillaumeSTEIN/7a4ece3c6bb487d16df0
    Here is a diff (1 year available) : https://www.diffnow.com/?report=8zhe9
    Have fun

    Ist this still not implemented?

    @GuillaumeSTEIN I tried your full version script, nothing seems to change.
    Do I need to add some special parameters or classes to HTML to make it work?
    Maybe you can make a working example on http://codepen.io/ or jsfiddle?

    Yes, you need to set option : group_selectable to true to activate this feature

    thanks @GuillaumeSTEIN , it worked, but what I miss from @adriengibrat script, is highlighting all options under current group.

    selected groups have a "result-selected" class.
    You can do some CSS. Here is what I have written, you may need to adapt it for your needs :

     select.form-control + .chosen-container-multi .chosen-results li.result-selected{
         display: list-item;
         color: #ccc;
         cursor: default;
         background-color: white;
     }
    

    I took a stab at it #2678

    This would be such a useful feature! I would love to see it implemented!

    +1 for this feature.

    If someone finds this useful, I grab @slothbear jsfiddle and improve it with :

    • "Clear all" button
    • Selecting root category item disables and deselects childrens. Why ? On my case, I would use chosen to generate a hierarchy filter, where selecting a father node implicates that would search on every children category, and we not desire to pollute the UI putting every children as selected.

    http://jsfiddle.net/Zardoz/pf6dhrbc/6/

    I just upgraded to chosen 1.8.3 in order to get the results to stay open after selecting a result on a multiple select (added in version 1.7.0). Great feature, glad it was added. However, I had been using 1.6.1 and used the code here to allow an entire group to be added when clicking the group name: http://robido.com/jquery/add-selectdeselect-optgroup-click-events-harvests-chosen-jquery-plugin/

    That code has been working great, until now. Using 1.8.3 and hide_results_on_select:false causes something to break, and it only selects the currently highlighted result option. When that line is removed (setting it back to default of true, hide upon select), it works fine and selects the entire group results options. So something in the hide_results_on_select:false is breaking/interfering with the ability to gather all the not .result-selected under a .group-result. Sacrificing this ability for the new feature is brutal.

    I'll look through all the above comments to see if this has been addressed as a flaw of the new feature, but I can't tell which version people are using when they are testing this.

    Any ideas?

    okay. i've had enough. "upgrading" to 1.8.3 has been nothing but a game of whack a mole for the last week. css issues, unexpected activity issues, etc. i upgraded to get the keep results open on multi select feature (which took years to implement in the first place), but discovered it always jumps back to top when selecting from the results, so what good is that - all that waiting for nothing. performance on a single select with many options has slowed to a crawl somehow. and more issues too many to list here. good job keeping this thing going for so many years, i've enjoyed it. but the improvements came at a cost of degrading user experience and i can't have that. am researching how to pull out chosen and use select2. it's 2018, time to find a select tool that keeps up with user expectations which keep getting tougher to meet. sorry and thanks

    I've moved to select2 too, but I didn't take a dump on chosen before that. You have a weird way of saying "thanks".

    Hello,
    If you wish to use optgroup and be able to click on it and automatically add all the options of that group, just add this to your javascript : (the event trigger ".group-result" can be more restrictive)

    I'm sure this can be added to the AbstractChosen class, with something like AbstractChosen.prototype.optgroup_click = function(evt) ....

    $('body').on('click','.group-result',function(){
        // id of select
        var quest=$(this).parent().parent().parent().attr('id');
        quest='#'+quest.substring(0,quest.lastIndexOf('_'));
        // number of optgroup
        var total=$(quest+' optgroup').length;
        // number of group after group-result clicked
        var nb=0;
        $(this).nextAll().each(function(){
            if($(this).hasClass('group-result'))nb++;
        });
        // for clicked group-result, select options in the right select tag by position
        $(quest+' optgroup:nth-of-type('+(total-nb)+')').children().each(function(){
            $(this).prop('selected','selected');
        });
        // update chosen !
        $(quest).trigger('chosen:updated');
    });
    

    I made use of bootstrap-select and was also struggling to find something to be able to click on the optgroup and select all its items - This link actually worked for me, hope it helps :https://stackoverflow.com/questions/41821115/select-deselect-optgroup-based-on-option-select-in-select-picker-boostrap

    Was this page helpful?
    0 / 5 - 0 ratings

    Related issues

    alexfrancavilla picture alexfrancavilla  ·  9Comments

    jbrooksuk picture jbrooksuk  ·  6Comments

    scottdoc picture scottdoc  ·  7Comments

    kafoso picture kafoso  ·  5Comments

    mcclurem picture mcclurem  ·  4Comments