0

Trying to get my second select element's options to populate from an array based on the value of the first select element. I can't seem to understand why it only populates the items from the array of the first select element. I know the appendChild is causing the items to keep tacking on at the need, but I've tried to clear the variables, but it seems the option elements that were created stay.

Any help would be great, thanks!

<select id="makeSelect" onChange="modelAppend()">
    <option value="merc">Mercedes</option>
    <option value="audi">Audi</option>
    <option value="bmw">BMW</option>
</select>

<select id="modelSelect">

</select>

<script>
var audiModels = ["TT", "R8", "A4", "A6"]; //audimodels
var mercModels = ["C230", "B28", "LTX",]; //mercmodels
var bmwModels = ["328", "355", "458i",]; //bmwmodels
var selectedMake = document.getElementById("makeSelect"); //grabs the make select
var selectedModel = document.getElementById("modelSelect"); //grabs the model select
var appendedModel = window[selectedMake.value + "Models"]; // appends "Models" to selectedMake.value and converts string into variable

function modelAppend() {
    for (var i = 0; i < appendedModel.length; i ++) { // counts items in model array
        var models = appendedModel[i]; // // sets "models" to count of model array
        var modelOptions = document.createElement("option"); //create the <option> tag
        modelOptions.textContent = models; // assigns text to option
        modelOptions.value = models; // assigns value to option
        selectedModel.appendChild(modelOptions); //appeneds option tag with text and value to "modelSelect" element
    }
}

</script>
6
  • How about editing your question and indenting your code properly? Commented Jul 7, 2017 at 19:40
  • this variable 'appendedModel' needs to be refreshed inside the function to take the new selectedMake value Commented Jul 7, 2017 at 19:45
  • @ScottMarcus How about providing appropriate feedback and recommending documentation that introduces indentation best practices? Commented Jul 10, 2017 at 3:10
  • @S.Morrison That's what Google is for. My feedback is absolutely appropriate. If you want help on programming from programmers, you have a responsibility to ask questions written with basic standards so that your question can be easily read and understood. Code indentation is literally "101" stuff. The text of your question implies that you have some understanding of coding, so it's perfectly appropriate to ask you to do this. Commented Jul 10, 2017 at 11:33
  • I see where you are coming from now and I can see why this is expected. I think the misunderstanding here comes from the "The text of your question implies that you have some understanding of coding" and my understanding of what guidelines should be followed before asking a question. Commented Jul 10, 2017 at 14:28

1 Answer 1

2

This line is fishy:

var appendedModel = window[selectedMake.value + "Models"];

You need to get the element when the value has changed, not on page load. Then you need to remove the options on change too, or you will get a very long list if the user selects multiple times. Use an object to store the arrays, that makes it much easier to access them later. Also better use an event listener instead of inline js (though that's not the main problem here).

Try below code:

let models = {
  audiModels: ["TT", "R8", "A4", "A6"],
  mercModels: ["C230", "B28", "LTX"],
  bmwModels: ["328", "355", "458i"]
}

document.getElementById('makeSelect').addEventListener('change', e => {
  let el = e.target;
  let val = el.value + 'Models';
  let appendTo = document.getElementById('modelSelect');
  Array.from(appendTo.getElementsByTagName('option')).forEach(c => appendTo.removeChild(c));
  if (!models[val] || !Array.isArray(models[val])) {
    appendTo.style.display = 'none';
    return;
  }
  models[val].forEach(m => {
    let opt = document.createElement('option');
    opt.textContent = opt.value = m;
    appendTo.appendChild(opt);
  });
  appendTo.style.display = '';
});
<select id="makeSelect">
    <option value=""></option>
    <option value="merc">Mercedes</option>
    <option value="audi">Audi</option>
    <option value="bmw">BMW</option>
</select>

<select id="modelSelect" style="display:none">

</select>

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

5 Comments

Awesome, this goes above and beyond to answer my question while pushing me in the direction of best practices. Thanks a ton!
You're welcome @S.Morrison . Let me know if you need explanation on what the lines do. Please mark the answer as accepted if it helped you.
After reviewing this I am a little confused on what is going on with the e => { ... ... ... return; } function. I understand that you are grabbing the element with the id "makeSelect" and adding an event listener to execute the function contained when the "makeSelect" element has changed, but why e =>, is that counting the values contained within "makeSelect"? Are you doing the same with the variable m in the function after that?
No @S.Morrison, that's simply an arrow function. In this context, it does the same as function(e) {... ... ... return;}
@S.Morrison e is the same in both ways, the change event. I grab the element that changed makeSelect with e.target. m is an element of the array, one after the other as it is in the forEach, e.g. TT for Audi -> TT

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.