tags:

views:

661

answers:

6

Hi!!

I have a listbox and I must limit its selection up to 5 items. If a 6th item is selected, I want to "deselect" it.

But, I'm having some problems on finding the last selected item and "deselect" it. And the last item selected it's necessary the $("#mySelect option:last")...

How can I get the selected item of a listbox??

Thanks!!!

+2  A: 

the :last part of your selector will select the "last" physical item in the select list (it doesn't relate to whether it is selected or not).

AFAIK, you need to iterate over the options, and test if each is selected (to get your count) or use the :selected pseudo selector.

//Or as noted by @peirix you can try to get it with :selected.
//Note that this will just clear the last (by rendered order) selection...
//not the "last" option that was selected.

if($("#mySelect option:selected").size() >= 6){
  $("#mySelect option:selected:last").attr('selected', null);
}

UPDATE:

Wow, this was more complex than I thought!... below is a tested example that works... it could likely be cleaner, but I'll leave that to others to hack ;-)

<script>
  $('#mySelect').bind('change', function(){
    if($("#mySelect option:selected").size() == 5){
      //5 picked, (re)store them...
      var sel = [];
      $("#mySelect option").each(function(i){
        if($(this).attr('selected')){
          sel[i] = true;
        } else {
          sel[i] = false;
        }
      });
      $(this).data('selectedIndexes',sel);
    } else if($("#mySelect option:selected").size() >= 6){
      //too many reset to orig...
      $("#mySelect option").each(function(i){
        if($(this).parent().data('selectedIndexes')[i]){
          $(this).attr('selected', 'selected');
        } else {
          $(this).attr('selected', '');
        }
      });
    }
  });
</script>

sample HTML:

<select id="mySelect" multiple="multiple" size="12">
  <option value="a">aaaaaaaaaaaa</option>
  <option value="b">bbbbbbbbbbbb</option>
  <option value="c">cccccccccccc</option>
  <option value="d">dddddddddddd</option>
  <option value="e">eeeeeeeeeeee</option>
  <option value="f">ffffffffffff</option>
  <option value="g">gggggggggggg</option>
  <option value="h">hhhhhhhhhhhh</option>
  <option value="i">iiiiiiiiiiii</option>
  <option value="j">jjjjjjjjjjjj</option>
  <option value="k">kkkkkkkkkkkk</option>
  <option value="l">llllllllllll</option>
</select>
scunliffe
$("#mySelect option:selected:last").val(); --> this will NOT get the last selected item, but the last physical selected. I've already tried this ehehe It was the first thing came up to mind, but it didn't work too
AndreMiranda
@AndreMiranda - correct. If the desire is to remove the last physical selection, you will need to hook into the onchange event, and keep some sort of tally of what options were previously selected.
scunliffe
Thanks for your answers scunliffe.. I will show some alert... it will be my life easier for now... hehe
AndreMiranda
yeah, I tried a heuristic attempt binding to onchange, and storing the selections using .data() on the select element... but it seems to be waaay more complicated than it should be. I'll post the code later when I get it working, but I don't have the time ATM to fully debug it. :-(
scunliffe
updated with a working version! ;-)
scunliffe
A: 

This should do the trick:

$("#mySelect option:checked:last").val(); //or not

A small re-write of Cory Larson's answer:

$("#mySelect option").mousedown(function() {
   if ($("#mySelect :checked").length > 5) {
      return false;
   }
   return true;
});

This will just not let the user check another option when the maximum number has been reached. And you could probably write out something to the user explaining that the maximum number has been reached.

peirix
it didn't work it :-(
AndreMiranda
A: 

Do you have to get the last one? Can't you just count how many are selected and then prevent further selections?

This function will check that the given SELECT element contains fewer than 'maximum' selected options.

function checkLimits( list, maximum ) {
    var options = list.options;
    var size = options.length;
    var numSelected = 0;

    for( var i = 0; i < size; ++i ) {
        if( options[ i ].selected ) ++numSelected;
    }
    if( numSelected > maximum ) {
        alert( 'You have selected more than ' + maximum + ' options.\n' +
            'Please deselect ' + ( numSelected - maximum ) + ' option(s) then
            try again.' );
        return false;
    }
    return true;
}

To call it directly from a form's onsubmit event, you could do:

<select ... onsubmit="return checkLimits(this.listName, 2)">

You could jQueryify it, but this should get you started. Taken from http://bytes.com/topic/javascript/answers/93760-please-help-limit-number-selections-multiple-select-list-box#post316514

Cory Larson
Hi Cory! I already could make to count the selected options, but I'm avoiding to throw some alert saying that the user should deselect xx options. I'm trying to accomplish something more automatic by deselecting the last selected item (not the last selected physical item)
AndreMiranda
I think I will throw an alert anyway... it will be more pratical than making some jquery's mind burned
AndreMiranda
+4  A: 

This will do it, although there is a brief "flash" of selection (you might want ot have a <span> show up underneath the <select> to say something like Maximum selection reached).

$('#mySelect').click(function(e) {
  if ($('option:selected',this).length > 5) {    
     $(e.target).removeAttr('selected');  
  }
});

I'll leave it as an exercise for you to get it working with keyboard selectivity too.

Here's a Working Demo

EDIT:

Ok, I'll admit that this is not the first time that I have been stung by also not testing an answer in IE too (there seem to be a lot of problems with <select> elements in IE), but here is a flexible solution that I have tested in IE 6 and Firefox 3.5.3 and it works in both. I've wrapped it in a plugin, in case you need this on more than one page

(function($) {

$.fn.maxLimitSelect = function(max) {

  if (!max || !/^\d+$/.test(max)) return this;

  return this.each(function() {

    $(this).bind("click change keypress",{ max: max },function(event) {

      var options = $('option', this);
      var max = event.data.max;
      var selected = $('option:selected', this);
      var indexes;

      if (selected.length === max) {  
       indexes = $.map(options, function(e, i) { 
                   if(e.selected) return i; 
                 }); 
       $.data(this, "indexes", indexes);
      }
      else if (selected.length > max) {
       indexes = $.data(this, "indexes");
       options
         .removeAttr('selected')
         .each(function() { 
           var $this = $(this);
           if ($.inArray($this.prevAll().length, indexes) !== -1) {  
             $this.attr('selected','selected');
           }
         });   
      } 
    });
  });
}

})(jQuery);

Then to use, it's simply

$('#mySelect').maxLimitSelect(5);

passing in the maximum number of items that can be selected. This works with key and mouse selections in both IE and Firefox versions tested although interestingly, IE 6 doesn't appear to support the Ctrl hold and Space to select multiple items, but does allow holding Shift to select a number of contiguous items. The plugin does limit this to the passed in max.

Here's a Working Demo

Russ Cam
Wow... we posted more or less the same exact solution within 3 seconds of each other.
KyleFarris
"With our powers combined, we are... Captain jQuery!"
Russ Cam
Lol... I loved that show. What magical rings must combine to make captain jQuery?
KyleFarris
I had a few bugs in my original code. They were fixed by looking at yours. Oh well... at least one of us Captain jQuery.
KyleFarris
The Selector ring, The plugin ring, The utility ring, The event ring, The ajax ring and *possibly* the callback ring. Of course, the selector ring is the most powerful, but it doesn't really belong to Captain jQuery, he borrowed it from Super Sizzle Man :)
Russ Cam
my updated solution below http://stackoverflow.com/questions/1600770/how-can-i-get-the-last-selected-value-in-a-listbox-with-jquery/1600793#1600793 will handle both mouse and keyboard selection.
scunliffe
@Russ, +1 for making it into a plugin. You've shown great effort on this one. ;-)
KyleFarris
+1  A: 

This will basically listen for any options that get clicked. If one gets clicked, the script checks to see how many total options are selected (including the one just clicked on). If the number of selected options is more than 5, the most-recently-clicked item will become "deselected".

$("#mySelect").click(function() {
    var num_selected = $('#mySelect option:selected').length;
    if(num_selected > 5) {
        $(e.target).removeAttr('selected');
    }
});

If you'd like to let people know why their option just became deselected, you can do this:

$("#mySelect").click(function(e) {
    var num_selected = $('#mySelect option:selected').length;
    if(num_selected > 5) {
        $(e.target).removeAttr('selected');
        alert('You are limited to 5 options at a time...');
    }
});

Hope that works out for you. This code was inspired by peirix.

KyleFarris
A: 

This seems to work on a little test page I did:

$('#mySelect option:selected:gt(4)').removeAttr('selected')
Brother Erryn