0

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 />

3
  • 2
    post a working snippet of what you have. screenshots don't cut it. Commented Jan 9, 2020 at 22:44
  • @DCR Have edited the question to include code. Commented Jan 9, 2020 at 23:03
  • 1
    Does doing it "the other way around" mean that when you choose a Model (from a list of all Models for all Makes), the Make input is automatically populated? Commented Jan 9, 2020 at 23:34

1 Answer 1

1

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?

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, Thank you so much for your answer. However, I see that the make dropdown always has all the options there. Is there a way to only keep make that is associated with the model in the model dropdown. I have been trying to figure it out all day with no luck. To answer your question, I see how that would be a problem I plan to add a button that should reset the filters.
Never Mind, Figured it out!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.