'Toggle not working for DOM rendered HTML elements after reloading

I'm making a weather app and I want to click a button to convert between imperial and metric. I also have a search bar and when I enter a location, a dropdown menu would appear and I can click on one of the items and the HTML page would reload with new info.

Before clicking on any dropdown item (with initial values on the page), the toggle button works fine. But after I click on a dropdown item and the page reloads, the button works only for HTML elements that I wrote directly into the .html file. For the other elements that I wrote into HTML through DOM, it doesn't work.

Relevant code below.

async function init (name) {
  await fetchCurrentData(name)

  const forecastHoursList =  await hoursList(name)
  document.querySelector('.forecast ul').innerHTML = renderHourlyForecast(forecastHoursList)

  const forecastDailyList =  await dailyList(name)
  document.querySelector('.future ul').innerHTML = renderDailyForecast(forecastDailyList)
}


// initial value
await init('Miami')


// toggle function below
const button = document.querySelector('button')
const hidden = document.querySelectorAll('span.hidden')
const visible = document.querySelectorAll('span.toggle')

button.addEventListener('click', event => {
  hidden.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })
  visible.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })


//Render data into HTML elements
const renderHourlyForecast = (forecastHoursList) => {
  const renderedForecastList = forecastHoursList.map((el) => {
    return `
    <div>
      <li>
        <ul>
          <li><h4>${el[0]}</h4></li>
          <li><img src="${el[1]}"></li>
          <li><span class="toggle" style="float: left">Temp °C</span><span class="hidden" style="float: left">Temp °F</span><h4 class="temp">${el[2]}</h4></li>
          <li><span class="toggle" style="float: left">Feels °C</span><span class="hidden" style="float: left">Feels °F</span><h4 class="temp">${el[3]}</h4></li>
          <li><span class="toggle" style="float: left">Wind kph</span><span class="hidden" style="float: left">Wind mph</span><h4 class="windspeed">${el[4]}</h4></li>
          <li><span style="float: left">Cloud cover</span><h4>${el[5]}%</h4></li>
          <li><span style="float: left">Precip chance</span><h4>${el[6]}%</h4></li>
        </ul>
      </li>
    </div>
    `
  }).join('')
  return renderedForecastList
}


//Searchbar input event below
const onInput = async event => {
  const cityList = await autoComplete(event.target.value)

  if(!cityList.length) {
    dropdown.classList.remove('is-active');
    return
  }

  resultsWrapper.innerHTML = ''
  dropdown.classList.add('is-active');

  for(let list of cityList) {
    const option = document.createElement('a')
    option.classList.add('dropdown-item')
    option.innerHTML = renderOption(list)

    //Dropdown click event below
    option.addEventListener('click', async () => {
      dropdown.classList.remove('is-active');
      search.value = list[0];
      await init(list[0])
    });

  resultsWrapper.appendChild(option)
  }
}


Solution 1:[1]

The button works only for HTML elements that I wrote directly into the .html file. For the other elements that I wrote into HTML through DOM, it doesn't work.

This is happening because you used innerHTML+= as the DOM Subtree of the main element is completely reconstructed, the event handlers are destroyed. Better use the event.target to check whether the element clicked is a dropdown element or not.

For example

const fruits = ['Pineapple', 'Coconut', 'Mango'],
  list = document.querySelector('ul');

fruits.forEach(fruit => {
  list.innerHTML += `<li>${fruit}</li>`
})

list.addEventListener('click', e => {
  if (e.target.tagName.toLowerCase() === 'li')
    e.target.innerText = e.target.innerText.split('').reverse().join('');
})
<ul>
  <li>Apple</li>
</ul>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Joy Dey