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);
};
Some of the issues:
The event handlers will only be attached when all asynchronous responses have come in. This means there is ample time for some inserted elements to not have handlers attached to them. It would make sense to attach a button handler in the displayTickerResults
function, right when it is created. There seems no good reason to delay that.
If this process is executed more than once, then it looks like the buttons that were already on the page will receive a second event handler for doing the same job. A click on such a button will execute the same kind of handler twice.
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.