James Glass
James Glass

Reputation: 4300

Iterating over options from multiple select boxes in jQuery

I have several select boxes (the exact number is dynamic), each containing the same values. When an option is selected in one box, I want to disable this value in all the other select boxes.

As shown in this jsFiddle, when you select a value in the first select box, it correctly disables that value in the second select box. When you select a value in the second select box, the code correctly disables that value in the first select box; however, it enables (i.e. does not disable) the original selected value from the first select box, in the second box.

To replicate: select Value One for the first select box. Value One is correctly disabled in the second select box. Now select Value Two in the second select box. It's disabled in the first select box, but now Value One is incorrectly enabled in the second select box.

After hours of trying to diagnose the issue, it seems that my .each statement only processes the first select box, and does not advance to the second select box to iterate over it's values. Edit: Actually it doesn't stop processing; if you remove line 22-24 from the jsFiddle (the else statement that enables the values that are no longer selected), and then select Value One then Value Three in the first select box the code correctly processes the second select box and disables Value One and Value Three. So it's a problem with the multiple iterations over selectedAreas?

How can I iterate over all the options from all the select boxes on the page with my area_select class?

My jQuery:

$(function() {
    $(document).on('change', '.area_select', function (e) {
        generateSelectedAreas();            
    });
});

function generateSelectedAreas()
{
    var selectedAreas = new Array();

    //Get all the currently selected areas
    $('.area_select option:selected').each(function () {
            if ($(this).val() != '') {
                selectedAreas.push($(this).val());
            }
    });

    //The selectedAreas array contains all the correct values, as shown here
    console.log(selectedAreas);

    $('.area_select>option:not(:selected)').each(function () {
        for(var counter=0; counter < selectedAreas.length; counter++) {
            if (selectedAreas[counter] == $(this).val()) {
                $(this).attr("disabled", true);
            }
            else {
                $(this).attr("disabled", false);    
            }
        }       
    });

    return selectedAreas;
}

Upvotes: 0

Views: 2294

Answers (1)

Dom
Dom

Reputation: 40459

Okay this is a little complicating but I will do my best to explain what is going on here.

The main problem stems from the following statement:

$('.area_select>option:not(:selected)').each(function () {
    for(var counter=0; counter < selectedAreas.length; counter++) {
        if (selectedAreas[counter] == $(this).val()) {
            $(this).attr("disabled", true);
        }
        else {
            $(this).attr("disabled", false);    
        }
    }       
});

Say that I have two select elements:

Select 1
---------
Value 1 
Value 2
Value 3
Value 4

Select 2
---------
Value 1 
Value 2
Value 3
Value 4

You iterate through each option not currently selected:

Select 1 (Selected Value 3)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 4 (Enabled)

Select 2 (Selected Value 4)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 3 (Enabled)

selectedAreas = ['Value 3', 'Value 4']

you then go through each individual value in selectedAreas and say

if the selectedArea value is equal to the current option then disable it, or else enable it

Now look what happens when you go through each value:

If Option Equals Value 3

Select 1 (Selected Value 3)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 4 (Enabled)

Select 2 (Selected Value 4)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 3 (Disabled)

If Option Equals Value 4

Select 1 (Selected Value 3)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 4 (Disabled)

Select 2 (Selected Value 4)
---------
Value 1 (Enabled)
Value 2 (Enabled)
Value 3 (Enabled)

You see, it overlaps.

What you want to do is the following:

$(function() {
    $(document).on('change', '.area_select', function (e) {
        generateSelectedAreas();            
    });

    function generateSelectedAreas()
    {
        //enable all options, otherwise they overlap and cause probl
        $('.area_select option').each(function () {
            $(this).prop('disabled', false);
        });

        $('.area_select option:selected').each(function () {
           var select = $(this).parent(),
           optValue = $(this).val();

           if($(this).val()!=''){
               $('.area_select').not(select).children().filter(function(e){
                   //filters all children equal to option value
                   if($(this).val()==optValue)
                       return e
               }).prop('disabled', true);
           }
        });
    }
});

DEMO: http://jsfiddle.net/dirtyd77/J6ZYu/3/

Sorry for the long explanation! Hope this helps and let me know if you have any questions!

Upvotes: 1

Related Questions