mflodin
mflodin

Reputation: 1113

Select all options in optgroup

I have a select element with grouped options. I need to select (or deselect) all options in an optgroup when an option is clicked. I also need to be able to have multiple optgroups being selected at once.

The way I wish it to work is this:

Looking at other answers on Stack Overflow I created the following:

HTML:

<select multiple="multiple" size="10">
    <optgroup label="Queen">
        <option value="Mercury">Freddie</option>
        <option value="May">Brian</option>
        <option value="Taylor">Roger</option>
        <option value="Deacon">John</option>
    </optgroup>
    <optgroup label="Pink Floyd">
        <option value="Waters">Roger</option>
        <option value="Gilmour">David</option>    
        <option value="Mason">Nick</option>                
        <option value="Wright">Richard</option>
    </optgroup>
</select>

jQuery:

$('select').click(selectSiblings);
function selectSiblings(ev) {
    var clickedOption = $(ev.target);
    var siblings = clickedOption.siblings();
    if (clickedOption.is(":selected")) {
        siblings.attr("selected", "selected");
    } else {
        siblings.removeAttr("selected");
    }
}​

I made an example here: http://jsfiddle.net/mflodin/Ndkct/ (Sadly jsFiddle doesn't seem to support IE8 any more.)

This works as expected in Firefox (16.0), but in IE8 it doesn't work at all. From other answers I have found out that IE8 can't handle the click event on optgroup or option, which is the reason I bind it to the select and then use $(ev.target). But in IE8 the $(ev.target) still points to the entire select and not to the option that was clicked. How can I find out which option (or containing optgroup) that was clicked and whether it was selected or deselected?

Another unexpected behaviour, but minor in comparison, is that in Chrome (20.0) the deselect doesn't happen until the mouse leaves the select. Does anybody know a workaround for this? ​

Upvotes: 12

Views: 13630

Answers (6)

Anthony Johnston
Anthony Johnston

Reputation: 9584

not an answer to the specific question of select option cross browser issues, I think that's been answered already, but a solution to the problem of selecting the data and passing it back to the server would be to change your mark up to something which better suits multi selection

if you use checkboxes instead, you can put them in a list and add enhanching js to select all and deselect all

http://jsfiddle.net/Ndkct/43/

<dl>
<dt>Queen</dt>
<dd>
    <ul>
        <li>
            <input id="Mercury" name="bandmembers" value="Mercury" type="checkbox" />
            <label for="Mercury">Freddie</label>
        </li>    
        <li>
            <input id="May" name="bandmembers" value="May" type="checkbox" />
            <label for="May">Brian</label>
        </li>    
        <li>
            <input id="Taylor" name="bandmembers" value="Taylor" type="checkbox" />
            <label for="Taylor">Roger</label>
        </li>    
        <li>
            <input id="Deacon" name="bandmembers" value="Deacon" type="checkbox" />
            <label for="Deacon">John</label>
        </li>    
    </ul>
</dd>
<dt>Pink Floyd</dt> ...

The js is now simple enough

$("dt")
    .css("cursor","pointer")
    .click(function(){
        var $el = $(this).next();
        var $checks = $el.find(":checkbox");
        if($checks.is(":not(:checked)")){
           $checks.attr("checked",true); 
        }else{
           $checks.attr("checked",false); 
        }
    });

(this fiddle http://jsfiddle.net/Ndkct/44/ adds a parent checkbox to make it more usable)

Upvotes: 3

LazYChriS
LazYChriS

Reputation: 1

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>


$(document).ready(function() {
    $('select').click(function(tar) {
        var justClickValue = tar.target.value;

        var selectedGroup = $('option[value="'+justClickValue+'"]').parent();

        if (selectedGroup.hasClass("allSelected")) {
            selectedGroup.removeClass("allSelected");
            $("option").each(function() {
                $(this).removeAttr("selected");
            });
        } else {
            $(".allSelected").removeClass("allSelected");
            selectedGroup.addClass("allSelected");
            $(".allSelected option").each(function() {
                $(this).attr("selected", "selected");
            });
        }
    });
});

Upvotes: 0

potatosalad
potatosalad

Reputation: 4887

Since Internet Explorer as of version 10 still does not support any useful events on optgroup or option, any cross-browser solution to this issue can't depend on direct events from those elements.

Note: MSDN documentation claims that optgroup supports click events, but as of IE 10 that still does not seem to be a reality: http://msdn.microsoft.com/en-us/library/ie/ms535876(v=vs.85).aspx

I tested the following in Chrome 27, Firefox 20, Safari 6, IE 9, and IE 10 (I don't have access to IE 8 currently).

Here's an example you can play with: http://jsfiddle.net/potatosalad/Ndkct/38/

// Detect toggle key (toggle selection)
$('select')
    .on('mousedown', function(event) {
        // toggleKey = Command for Mac OS X; Control for others
        var toggleKey = (!event.metaKey && event.ctrlKey && !(/Mac OS/.test(navigator.userAgent))) ? event.ctrlKey : event.metaKey;
        if (toggleKey === true) {
            $(this).data('toggleKey', true);
        }
        $(this).data('_mousedown', true);
    })
    .on('mouseup', function() {
        $(this).data('_mousedown', null);
    });
// Chrome fix for mouseup outside select
$(document).on('mouseup', ':not(select)', function() {
    var $select = $('select');
    if ($select.data('_mousedown') === true) {
        $select.data('_mousedown', null);
        $select.trigger('change');
    }
});

$('select')
    .on('focus',  storeState)
    .on('change', changeState);

function storeState() {
    $(this).data('previousGroup', $('option:selected', this).closest('optgroup'));
    $(this).data('previousVal',   $(this).val());
};

function changeState() {
    var select = this,
        args   = Array.prototype.slice.call(arguments);

    var previousGroup = $(select).data('previousGroup'),
        previousVal   = $(select).data('previousVal');
    var currentGroup  = null,
        currentVal    = $(select).val();

    var selected = $('option:selected', select),
        groups   = selected.closest('optgroup');

    console.log("[change] %o -> %o", previousVal, currentVal);

    if ((previousVal === currentVal) && (groups && groups.length == 1)) {
        // selected options have not changed
        // AND
        // only 1 optgroup is selected
        // -> do nothing
    } else if (currentVal === null || currentVal.length === 0) {
        // zero options selected
        // -> store state and do nothing
        storeState.apply(select, args);
    } else { // a select/deselect change has occurred
        if ($(select).data('toggleKey') === true
            && (previousVal !== null && previousGroup !== null && groups !== null)
            && (previousVal.length > currentVal.length)
            && (previousGroup.length === groups.length)
            && (previousGroup.get(0) === groups.get(0))) {
            // options within the same optgroup have been deselected
            // -> deselect all and store state
            $(select).val(null);
            storeState.apply(select, args);
        } else if (currentVal.length === 1) {
            // single option selected
            // -> use groups
            currentGroup = groups;
        } else if (groups.length === 1) {
            // multiple options selected within same optgroup
            // -> use groups
            currentGroup = groups;
        } else {
            // multiple options selected spanning multiple optgroups
            // -> use last optgroup
            currentGroup = groups.last();
        }
    }

    $(select).data('toggleKey', null);

    if (currentGroup !== null) {
        $('optgroup', select).not(currentGroup).children(':selected').attr('selected', false);
        $(currentGroup).children(':not(:selected)').attr('selected', true);
        storeState.apply(select, args);
    }
};

It works by storing the previously selected group and options on the select element and determining which optgroup should be selected (or deselected).

Some behaviors can be changed based on the developers needs. For example in the case of selecting multiple options that span multiple optgroups (by clicking and dragging down as seen in screenshot):

multiple options selected spanning multiple optgroups

The default conflict resolution for this case is to always use the last optgroup, but could be changed to always use the first one, or the optgroup with the largest number of already selected options.

Upvotes: 2

Kesymaru
Kesymaru

Reputation: 129

this fix the problem, you only need to add this code after init chosen.

$( '.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' } )

Thanks to adriengibrat that posted this fix on github:
https://github.com/harvesthq/chosen/issues/323

Upvotes: 0

AkhilZ
AkhilZ

Reputation: 11

Hope this will work

$("#SelectID").live("click",function() {
var elements = this.options; //or document.getElementById("SelectID").options;
for(var i = 0; i < elements.length; i++){
   if(!elements[i].selected)
    elements[i].selected = true;
}
}

Upvotes: -1

Ram Lakhan Yadav
Ram Lakhan Yadav

Reputation: 31

According to your problem select/deselect all option. you can try following code , may be help you.

code:

javascript code:

 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js">

       $(function(){

                $('#allcheck').click(function(){
                var chk=$('#select_option >optgroup > option');
                chk.each(function(){
                  $(this).attr('selected','selected');
            });
   });  
$('#alluncheck').click(function(){

              var chk=$('#select_option >optgroup > option');
              chk.each(function(){
              $(this).removeAttr('selected');
          });
     });});

HtML CODE:

       <select multiple="multiple" size="10" id="select_option" name="option_value[]">
          <optgroup label="Queen">
            <option value="Mercury">Freddie</option>
            <option value="May">Brian</option>
            <option value="Taylor">Roger</option>
            <option value="Deacon">John</option>
        </optgroup>
        <optgroup label="Pink Floyd">
            <option value="Waters">Roger</option>
            <option value="Gilmour">David</option>    
            <option value="Mason">Nick</option>                
            <option value="Wright">Richard</option>
       </optgroup>
 </select>
<br>
       <strong>Select&nbsp;&nbsp;<a style="cursor:pointer;" id="allcheck">All</a>
  &nbsp;|&nbsp;<a style="cursor:pointer;"  id="alluncheck">None</a></strong>

Upvotes: -1

Related Questions