javascripthtmlbuttonasync-awaitinsertadjacenthtml

Appended div does not have functionality


My async function pulls info from web and appends to page using displayTickerResults() using insertAdjacentHTL. The HTML insert is using class names and structure that is the same as existing div's already on page. The renderButts() function is working, b/c the divs that already exist on page, after function is run, will start to work and the newly appended div's do not. Intuition is when renderButts() is ran the newly appended div's do not exist yet. Looking for solution to add functionality to newly appended buttons. Using Bootswatch for css. I have tried to use onclick="return rederButts()" which has not worked. I have tried placing the call of renderButts() in several different places as well.

const renderButts = function() {
    for (let i=0; i < accordBtns.length; i++) {
        accordBtns[i].addEventListener('click', function() {
            // console.log(accordBtns);
            accordText[i].classList.toggle('collapse')
        })
    };
};

 async function getStockResults(stock) {
    try {
        const tickRes = await fetch(`${baseURL}${stock}`);
        const tickerData = await tickRes.json();
        tickerData.forEach(val => {
            displayTickerResults(val);
        });
    } catch (error) {
        console.log(error);
    } finally {
        renderButts()
    }
}

this code comes before the above functions. Just showing to be thorough. Will expand on this function as soon as I get button functionality:

const displayTickerResults = function(arr) {
    // console.log(arr);
    const tickerHTML = `<div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
        Accordion Item #1
      </button>
    </h2>
    <div  class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#accordionExample" style="">
      <div class="accordion-body">
            Stock price equals this. And the ticker is  boi!
         </div>
    </div>
  </div>`;
  accordContainer.insertAdjacentHTML('beforeend', tickerHTML);
};

Solution

  • Some of the issues:

    A better approach would be to just define a one-for-all click handler at the very start, when there are no dynamically created buttons yet, using the principle of event delegation.

    accordContainer.addEventListener("click", function(e) {
        // Test where the click orinated
        const button = e.target;
        // Was it one of the buttons?
        if (!button.classList.contains("accordion-button")) return; // something else
        // Find the button's ancestor that contains the collapsible content.
        button.closest(".accordion-item")
              .querySelector(".accordion-collapse") // select that collapsible element
              .classList.toggle("collapse") // ...and toggle
    });
    

    Execute this code as soon as accordContainer has been initialised -- not when doing the requests.