Jquery selector to get all dropdown values, issues

2020-03-26 12:27发布

问题:

HTML Table

Row#1 : Col 1 [Country DropDown] | Col #2 [StateDropDown]

Row#2 : Col 1 [Country DropDown] | Col 2 [StateDropDown]

table has 2 dropdownlists, for Country & State - this works on one dropdown, but its disabling other/state dropdowns as well!

Problem is, while both USA and Aust have diff states selected text, but in col2 endup with same selected State ID/value 3 (If I select California, Perth is also Disabled!, hence my code is disabling them as duplicates since its comparing the selected value and not text) for e.g. this selection disables Perth..

[USA]      ->    [California]  (value = 3)
[Australia] ->   [Perth]       (*also* has value= 3) so its disabled

How to do this as a unique combination of both country & state in each row? or just compare texts of the dropdowns?...

  1. i.e. Option1, how to check if both Country ID + State ID Value already exist?
  2. Option2, Just compare the selected texts (feels half baked)

JS Fiddle

// Javascript Does not disable States previously selected
$("#CountryTable").on('change', '.State', function() {
var dropDownText = $('#CountryTable .State select').not(this).map(function()                {
 return this.SelectedText; // does not work this.val() works but useless
}).get();
var selectedValue = $(this).val();
var otherDropdowns = $('.State').not(this);

otherDropdowns.find('option[value=' + selectedValue + ']').prop('disabled', true); });


<table id="CountryTable">
<tbody id="CountryTableBody"> 
    <tr class="row">
        <td>
            <select>
                <option value="1">Country A</option>
                <option value="2">Country B</option>
                <option value="3">Country C</option>
            </select>               
        </td>

        <td>
            <select>
                <option value="1">State 1</option>
                <option value="2">State 2</option>
                <option value="3">State 3</option>
                <option value="4">State 4</option>
                <option value="5">State 5</option>
            </select>               
        </td>           
    <tr>  <!-- in JS prevent previous selection -->
    <tr class="row">
       <td>
            <select>
                <option value="1">Country A</option>
                <option value="2">Country B</option>
                <option value="3">Country C</option>
            </select>               
        </td>
        <td>
            <select>
                <option value="1">State 1</option>
                <option value="2">State 2</option>
                <option value="3">State 3</option>
                <option value="4">State 4</option>
                <option value="5">State 5</option>
            </select>               
        </td>          
    <tr>    
</tbody>   


*** Image to show something similar... not accurate


回答1:

This is not a perfect solution which you just can copy/paste, but it's getting real close to what you want.

I made it as a whole function with 4 arguments:

  1. The real table, preferably an id
  2. The td, preferably a class
  3. The hidden table to be cloned, preferably an id
  4. The new row button, preferably an id

Leaving you free to name your things like you want in the HTML and not caring about to fix the MULTIPLE places where those 4 are used in the script.

Now... This is just a good start.
In fact, when user changes from "Country A" to "Country B", the state dropdown should be different!

This is the only issue I left... Since I don't know how you want to load those options.

It took me quit a lot time... I did it because I couldn't believe that such a "simple" request can be that complex... I had to crush it
;).

So here is the code (JS only) and a working CodePen demo.

var excusiveSelect = function(tableID,rowCLASS,dummyID,cloneBtn){   // Preferably ID, CLASS, ID, ID

  console.clear();

  // Cloning function
  var cloneRow = function(){
    var newrow = $(dummyID).find(rowCLASS).clone();
    $(tableID).append(newrow);
    refresh_mapping();
  };

  // Generate new lines
  $(cloneBtn).on("click",cloneRow);

  // ================================================================================ INITIALISATION
  // Selection mapping
  var row_count;
  var row_map = {};

  // Get select clas names per colums
  var col_count = $(rowCLASS).first().find("td").length;
  var col_classes = [];
  for(i=0;i<col_count;i++){
    col_classes[i] = $(document).find(rowCLASS).first().find("select").eq(i).attr("class").split(" ").join(".");
  }
  console.log("SELECT CLASSES: "+JSON.stringify(col_classes));

  var refresh_mapping = function(){
    row_count =  $(document).find(rowCLASS).length-1;
    console.log("ROWCOUNT: "+row_count);
    for(i=0;i<row_count;i++){

      row_map["row_"+i] = {};
      $(tableID).find(rowCLASS).eq(i).find("select").each(function(index){

        // Get the select classes as object attribute.
        var thisClasses = $(this).attr("class").split(" ").join(".");

        // For each row/select get the selected index.
        row_map["row_"+i][thisClasses] = $(this)[0].selectedIndex;
      });
    }
    console.log("VALUES MAPPING: "+JSON.stringify(row_map));
  }

  cloneRow();

  // ================================================================================ FROM COLUMN #1

  $(document).on("change","."+col_classes[0],function(){
    console.log("\n======================================================= Country change\n");

    refresh_mapping();

    // Disables options already selected in ALL col_classes[1] where col_classes[0] is the same
    for(i=0;i<row_count;i++){

      if( ( row_map["row_"+i][col_classes[0]] == $(this)[0].selectedIndex ) 
         && (  $(this).closest(rowCLASS).index() != i ) ){

        $(this).closest(rowCLASS).find("."+col_classes[1]+" option").eq( row_map["row_"+i][col_classes[1]] ).attr("disabled",true);

        // Else enable the option if not self
      }else{
        if( $(this).closest(rowCLASS).index() != i ){
          $(this).closest(rowCLASS).find("."+col_classes[1]+" option").eq(i).attr("disabled",false);
        }
      }
    }

  });

  // ================================================================================ FROM COLUMN #2

  $(document).on("change","."+col_classes[1],function(){
    console.log("\n======================================================= State change\n");
    console.clear();
    refresh_mapping();

    thisIndex = $(this)[0].selectedIndex;               // Option selectedIndex
    thisRowIndex = $(this).closest(rowCLASS).index();     // Row index

    // If same country...
    var thisCol0index = $(this).closest(rowCLASS).find("."+col_classes[0])[0].selectedIndex;


    $(tableID).find("."+col_classes[1]).each(function(){
      if( $(this).closest(rowCLASS).find("."+col_classes[0])[0].selectedIndex == thisCol0index ){

        // Zap tout les disabled
        $(this).find("option:not(:eq(0))").attr("disabled",false);

        // Use mapping to disable based on col_classes[0]
        for(i=0;i<row_count;i++){
          if( row_map["row_"+i][col_classes[0]] == thisCol0index ){

            $(this).find("option").eq(row_map["row_"+i][col_classes[1]]).attr("disabled",true);
          }
        }

      }
    });
  });
  // ================================================================================
}

// Init!
excusiveSelect("#CountryTable",".row","#DummyTable","#newRow");   // Preferably ID, CLASS, ID, ID