Sort dropdown list

2020-08-01 20:29发布

问题:

I am trying to sort a dropdownlist (selector) in html.

I have two lists, a pre-selection which then should be used to define the content of the secont list.

A short code sample:

<!doctype html>
<html class="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

</head>

<body>
<table width=100% border="0">
  <tr>
  <td>&nbsp;</td>
    <td>Product</td>
    <td><select name="product" id="product" width="300" style="width: 300px">
      <option></option>
      <option id="TLX">TLX</option>
      <option id="FLX">FLX</option>
      <option id="MLX">MLX</option>
    </select></td>
    <td>&nbsp;</td>
  </tr>
  <tr>
  <td>&nbsp;</td>
    <td>Power</td>
    <td><select name="power" id="power" width="300" style="width: 300px">
      <option></option>
      <option name="TLX">6</option>
      <option name="TLX">8</option>
      <option name="TLX">10</option>
      <option name="TLX">12</option>
      <option name="TLX">15</option>
      <option name="FLX">6</option>
      <option name="FLX">8</option>
      <option name="FLX">10</option>
      <option name="FLX">12</option>
      <option name="FLX">15</option>
      <option name="FLX">17</option>
      <option name="MLX">30</option>
      <option name="MLX">40</option>
      <option name="MLX">60</option>
    </select></td>
    <td>&nbsp;</td>
  </tr>
</table>

</body>
</html>

I want to b able to select the product and then must the power list be sortet accordingly.

For instance if TLX is choosen then only 6, 8, 10, 12, and 15 are shown as possibilities in the second list.

回答1:

using vanilla you can do like below

see the demo working http://jsfiddle.net/ST5dq/

no use name attribute, use data-name, value or other attribute, the name attribute not working cross browser to option tag...

i'll use data-name

<table width=100% border="0">
  <tr>
  <td>&nbsp;</td>
    <td>Product</td>
    <td><select name="product" id="product" width="300" style="width: 300px">
      <option></option>
      <option id="TLX">TLX</option>
      <option id="FLX">FLX</option>
      <option id="MLX">MLX</option>
    </select></td>
    <td>&nbsp;</td>
  </tr>
  <tr>
  <td>&nbsp;</td>
    <td>Power</td>
    <td><select name="power" id="power" width="300" style="width: 300px">
      <option></option>
      <option data-name="TLX">6</option>
      <option data-name="TLX">8</option>
      <option data-name="TLX">10</option>
      <option data-name="TLX">12</option>
      <option data-name="TLX">15</option>
      <option data-name="FLX">6</option>
      <option data-name="FLX">8</option>
      <option data-name="FLX">10</option>
      <option data-name="FLX">12</option>
      <option data-name="FLX">15</option>
      <option data-name="FLX">17</option>
      <option data-name="MLX">30</option>
      <option data-name="MLX">40</option>
      <option data-name="MLX">60</option>
    </select></td>
    <td>&nbsp;</td>
  </tr>
</table>

you can use this to sort the list

function sortDropdownList(ddl){

    var options = [].slice.apply(ddl.options, [0]);
    ddl.innerHTML = "";
    var sorted = options.sort(function(a,b){     
       return +(a.innerText) - +(b.innerText);
    });

    for(var i = 0; i < sorted.length; i++){
      ddl.options.add(sorted[i]);
    }  

}

you need pass a dom element, not a jQuery element.

to bind the select parent to select child you can do this

on you page initialize add the code

var parentSelect = document.getElementById("product");
var childSelect = document.getElementById("power");
var options = [].slice.apply(childSelect, [0]);
var emptyOption = options[0];
childSelect.innerHTML = "";

parentSelect.addEventListener("change", function(e){

    var selectedId = parentSelect.options[parentSelect.selectedIndex].id;
    childSelect.innerHTML = "";
    childSelect.options.add(emptyOption);
    for(var i = 0; i < options.length; i++){

        if( options[i].getAttribute("data-name") == selectedId ){

           childSelect.options.add(options[i]);

        }
    }

    sortDropdownList(childSelect);

});


回答2:

No attempt was made to be cross browser here… But there's only one browser I can think of that might give you trouble :)

Demo

Code

var product = document.getElementById('product');
var power   = document.getElementById('power');
var allOpts = power.getElementsByTagName('option');
var opts = {
    empty: allOpts[0]
};

// This builds three additional lists of options for each type of product
// It relies on having a single attribute - if more are added, this logic
// would need to be adjusted.
for(var i = 1; i < allOpts.length; ++i) {
    var name = allOpts[i].attributes[0].value;

    opts[name] = opts[name] || [];
    opts[name].push(allOpts[i]);
}

// Each time product is changed, just loop through based on the selected ID
// and add those options to the power select list (removing all children first)
product.addEventListener('change', function(evt) {
    var val = evt.target.value;

    power.innerHTML = '';
    power.appendChild(opts.empty);
    for(var i = 0; i < opts[val].length; ++i) {
        power.appendChild(opts[val][i]);
    }
});

Here is a version using documentFragment:

Demo

documentFragment version

var product = document.getElementById('product');
var power   = document.getElementById('power');
var allOpts = power.getElementsByTagName('option');
var opts = {
    empty: allOpts[0]
};

// Appending to the doc fragment removes it from the live nodelist
while(allOpts.length > 1) {
    var name = allOpts[1].attributes[0].value;

    opts[name] = opts[name] || document.createDocumentFragment();
    opts[name].appendChild(allOpts[1]);
}

product.addEventListener('change', function(evt) {
    var val = evt.target.value;

    power.innerHTML = '';
    power.appendChild(opts.empty);
    power.appendChild(opts[val].cloneNode(true));
});

Update

With just a little more work, this can be made more generic - say when new requirements come in comments to the original answer :)

Additional requirements

Note: I added the empty option element to keep the solution simpler. The code can be adapted to handle the absence of it as well, but that will be left as an exercise for the reader.

<select name="continent" id="continent">'
    <option value="IMAGES/maps/europe_gray.png" id="EU">Europe</option>
    <option value="IMAGES/maps/europe_gray.png" id="AS">Asia</option>
</select>
<select name="country" id="country">
    <option></option>
    <option name="EU" id="ALB" value="IMAGES/flags/al.png">Albania, Republic of</option>
    <option name="AS" id="RUS" value="IMAGES/flags/ru.png">Russia</option>
</select>

With the changes below, the controller logic is now more generic in that it can adapt to the markup by accepting additional information that tells it where to find its keys and select elements.

Generic Controller Example

/* params {
 *    master: id of the master select element
 *    subord: id of the subordinate select element
 *    mKey:   name of the attribute holding the key in master that will be used to filter subordinate options
 *    sKey:   name of the attribute in subordinate that will be used to match against mKey
 */
function selectController(params) {
    var master = document.getElementById(params.master);
    var subord = document.getElementById(params.subord);
    var allOpts = subord.getElementsByTagName('option');
    var opts = {
        empty: allOpts[0]
    };

    // Appending to the doc fragment removes it from the live nodelist
    while (allOpts.length > 1) {
        var name = allOpts[1].getAttribute(params.sKey);

        opts[name] = opts[name] || document.createDocumentFragment();
        opts[name].appendChild(allOpts[1]);
    }

    master.addEventListener('change', function (evt) {
        var sel  = master.options[master.selectedIndex];
        var mKey = sel.getAttribute(params.mKey); 

        subord.innerHTML = '';
        subord.appendChild(opts.empty);
        subord.appendChild(opts[mKey].cloneNode(true));
    });
}

selectController({
    master: 'product',
    subord: 'power',
    mKey:   'id',
    sKey:   'name'
});

selectController({
    master: 'continent',
    subord: 'country',
    mKey:   'id',
    sKey:   'name'
});


回答3:

If you are using jquery, can be accomplished like so: Demo

$(document).ready(function(){    
    var powerOptions = $('#power option').hide();
    $('#product').change(function(){
        powerOptions.hide().filter('option[name=' + $(this).find('option:selected').val() + ']').show();
    });
});

Note: In product dropdown, change id attribute of each option to name.



回答4:

You need cascading dropdownlist

Please look at this links:

  • jQuery Cascading Dropdown Plugin(most advised link is the Demo page of this item)
  • Cascading drop down plugin for jQuery
  • Clear dropdownlist with JQuery

And you can find other links about cascading dropdownlists from google search or other...