Search code examples
javascripthtml

dynamically adding <option> elements to select tag destroys its functionality


Im trying to dynamically add options to a select tag based on certain conditions

https://jsfiddle.net/kvnhdpyg/

document.getElementById('metodode').addEventListener('click', function(e) {

  this.innerHTML = '';
  const elemento = document.createElement('option');
  elemento.text = 'Escolha uma opçao';
  elemento.value = '';
  elemento.disabled = true;
  elemento.selected = true;
  this.appendChild(elemento);

  for (let i = 0; i < 5; i++) {

    const elemento = document.createElement('option');
    elemento.text = "test123"

    this.appendChild(elemento);
  }
});
<select id="metodode" style="cursor:pointer;">
  <option id="first" value="" disabled selected>Escolha uma opçao</option>
</select>

here is the short form version of it, dynamically adding option tags to select destroys it's functionality, clicking on the dynamic option tags doesn't put its text in the select tag as it would with normal option tags

i've tried adding event listeners as well but it doesn't work, i can console.log() them but no click


Solution

  • That's because by using the click event handler, the event is occurring twice:

    • when you click the first time on the dropdown to pick an option
    • when you pick an option

    The second time it destroys the options list right when you were supposed to have picked one thus resetting the situation. Why exactly? because the selected option delivered an information being selected but you destroyed and recreated those just one moment after you set that state.

    You can verify this behaviour by adding a console.log in the event handler.

    Now it's worth saying it's a bad practice to have such a strategy but yet for the sake of finding a workaround, if you instead rely on the mousedown event, it will occur only when actually pressing the mouse button on the dropdown iteself.

    EDIT To be fair I realized that if you click the dropdown AFTER you already selected an option, the same nasty behaviour will reoccur resetting the selected option. Despite the main focus here was finding the reason behind that strange behaviour, I modified the snippet to address also this side effect I didn't consider before.

    document.getElementById('metodode')
      .addEventListener('mousedown', function(e) {
    
        //keep track of the currently selected option
        const currentValue = this.value;
    
        this.innerHTML = '';
        const elemento = document.createElement('option');
        elemento.text = 'Escolha uma opçao';
        elemento.value = '';
        elemento.disabled = true;
        elemento.selected = true;
        this.appendChild(elemento);
    
        for (let i = 0; i < 5; i++) {
          const elemento = document.createElement('option');
          elemento.text = "test123-" + i;
          elemento.value = i;
          this.appendChild(elemento);
        }
    
        //restore the previously selected option (if it exists)
        //I'm using a general approach just to fit with
        //further scenarios beyond this simple demo
        const options = [...this.options];
        const matchingOption =
          options.find(opt => opt.value === currentValue);
        if (matchingOption) {
          matchingOption.selected = true;
        }
      
    });
    <select id="metodode" style="cursor:pointer;">
      <option id="first" value="" disabled selected>
        Escolha uma opçao
      </option>
    </select>