Anuradha Pandey
Anuradha Pandey

Reputation: 11

Dynamic Dropdown in Javascript with onchange

I am pretty new to JavaScript. I am trying to create dropdowns that are dynamic in the sense that when you select a value in the first dropdown the second dropdown automatically updates for all possible values for the value selected and vice versa.

I am able to do it one way but not the other way around. Please find attached the screenshot of my code here. I would be grateful for any answers. Thanks.

function populate(s1,s2){
  var s1 = document.getElementById(s1);
  var s2 = document.getElementById(s2);
  if (s1.value!=""){
    if (s1.value!=""){
      s2.innerHTML=""
    } else {
      s1.innerHTML=""
    }
    if(s1.value == "Chevy"){
      var optionArray = ["|","Camaro|Camaro","Corvette|Corvette","Impala|Impala"];
    } else if(s1.value == "Dodge"){
      var optionArray = ["|","Avenger|Avenger","Challenger|Challenger","Charger|Charger"];
    } else if(s1.value == "Ford"){
      var optionArray = ["|","Mustang|Mustang","Shelby|Shelby"];
    } 
    for(var option in optionArray){
      var pair = optionArray[option].split("|");
      var newOption = document.createElement("option");
      newOption.value = pair[0];
      newOption.innerHTML = pair[1];
      s2.options.add(newOption);
    }

  }
  if(s2.value == "Camaro" || s2.value=="Corvette"|| s2.value=="Impala"){
    var optionArray1 = ["|","Chevy|Chevy"];
  } else if(s2.value == "Avenger" || s2.value=="Challenger"|| s2.value=="ImpChargerala"){
    var optionArray1 = ["|","Dodge|Dodge"];
  } else if(s2.value == "Mustang" || s2.value=="MuShelby"){
    var optionArray1 = ["|","Dodge|Dodge"];
  }
  for(var option in optionArray1){
    var pair = optionArray[option].split("|");
    var newOption = document.createElement("option");
    newOption.value = pair[0];
    newOption.innerHTML = pair[1];
    s1.options.add(newOption);
  }
}
<h2>Choose Your Car</h2>
<hr />
Choose Car Make:
<select id="slct1" name="slct1" onchange="populate(this.id,'slct2')">
  <option value=""></option>
  <option value="Chevy">Chevy</option>
  <option value="Dodge">Dodge</option>
  <option value="Ford">Ford</option>
</select>
<hr />
Choose Car Model:
<select id="slct2" name="slct2">
  <option value=""></option>
  <option value="Camaro">Camaro</option>
  <option value="Corvette">Dodge</option>
  <option value="Impala">Impala</option>
  <option value="Avenger">Avenger</option>
  <option value="Corvette">Dodge</option>
  <option value="Challenger">Challenger</option>
  <option value="Charger">Charger</option>
  <option value="Mustang">Mustang</option>
  <option value="Shelby">Shelby</option>
</select>
<hr />

Upvotes: 0

Views: 87

Answers (1)

Cat
Cat

Reputation: 4246

Hopefully this should explain a lot. See the comments for why certain parts work the way they do.

This code could be shorter, but I wanted to make it more clear. (For more info about almost any JS feature, MDN is a good source. You can google the feature's name and MDN (like "Arrays MDN") to find results on that site.)

const

  // Identifies HTML elements in the DOM that we will need
  makesDropdown = document.getElementById("makesDropdown"),
  modelsDropdown = document.getElementById("modelsDropdown"),
  
  // Puts Makes and Models in a `cars` object for reference
  cars = {
    Chevy: ["Camaro", "Corvette", "Impala"],
    Dodge: ["Avenger", "Challenger", "Charger"],
    Ford:  ["Mustang", "Shelby"]
  }
;

// Calls the appropriate function when a selection changes
makesDropdown.addEventListener("change", updateModelsDropdown);
modelsDropdown.addEventListener("change", updateMakesDropdown);


// Defines listener functions
function updateModelsDropdown(event){
  let
    // The "target" of the `change` event is the input that changed
    thisMake = event.target.value,

    // Gets the array of models from `cars` (If no make is selected, uses all models)
    relevantModels = cars[thisMake] || getAllModels();
  modelsDropdown.selectedIndex = 0; // Shows the first (blank) option

  // The select element's children are the options
  let optionElements = modelsDropdown.children;
  for(let option of optionElements){
    
    // Uses CSS to hide (or unhide) HTML elements
    option.classList.add("hidden");

    // Keeps the blank option as well as the ones included in the array
    if(relevantModels.includes(option.value) || option.value === ""){
      option.classList.remove("hidden");
    }
  }
}

function updateMakesDropdown(event){
  let
    thisModel = event.target.value,
    relevantMake = "",

    // Gets an array of the "keys" for an object
    allMakes = Object.keys(cars);

  // Loops through the keys and tests each corresponding value (ie, each array of models)
  for(let make of allMakes){
    let models = cars[make];

    // Finds the key whose value includes the selected model
    if(models.includes(thisModel)){

      // Saves the name of the key so we can select it in the makesDropdown
      relevantMake = make;
    }
  }
  let optionElements = makesDropdown.children;
  for(let i = 0; i < optionElements.length; i++){

    // Finds the index of the matching value
    if(relevantMake === optionElements[i].value){

      // Selects the option by its index
      makesDropdown.selectedIndex = i;
    }
  }
}

// Defines a helper function
function getAllModels(){

  // Gets an array of the "keys" for an object
  const makes = Object.keys(cars);
  const models = []; // Starts with an empty array to push models into
  for(let make of makes){

    // `cars[make]` retrieves the value (array of models) for that key
    // `...` spreads the array into individual values (models)
    // `push` adds each model to the new `models` array
    models.push(...cars[make]);
  }
  return models;
}
.hidden{ display: none; }
<hr />
<h2>Choose Your Car</h2>
<hr /> Choose Car Make:
<select id="makesDropdown">
  <option value=""></option>
  <option value="Chevy">Chevy</option>
  <option value="Dodge">Dodge</option>
  <option value="Ford">Ford</option>
</select>
<hr /> Choose Car Model:
<select id="modelsDropdown">
  <option value=""></option>
  <option value="Camaro">Camaro</option>
  <option value="Corvette">Corvette</option>
  <option value="Impala">Impala</option>
  <option value="Avenger">Avenger</option>
  <option value="Challenger">Challenger</option>
  <option value="Charger">Charger</option>
  <option value="Mustang">Mustang</option>
  <option value="Shelby">Shelby</option>
</select>

Note:
Selecting the blank option in the "makesDropdown" automatically resets the "modelsDropdown" so all models are available for the next selection, as one might expect. However, selecting the blank option in the modelsDropdown has no such effect. How would you add this feature to improve user experience?

Upvotes: 1

Related Questions