Unable to select element after inserting it using insertAdjacentHTML

43 views Asked by At

I have this piece of code wherein I am making an API call and fetching some data and then inserting it onto the page so as to create an accordion style display panel. The rendering works fine but I am not able to select any element which I have inserted onto the page , for example console.log(btns) gives me an empty nodelist, hence I am not able to apply the event listener to it.

'use strict';
const quesContainer = document.querySelector('.container');

const renderData = function(mainTitle, quesTitle, tags, link1, link2, ytlink) {
  const html = `<button class="btn">hi</button>
      <div class="panel">
        <div class="topic">
          <div class="question">
            <p>
                <div class="mainTitle"><h1>${mainTitle}</h1></div>
                <div class="ques-title">${quesTitle}</div>
                <div class="link-1"><a href="${link1}">${link1}</a></div>
                <div class="link-2"><a href="${link2}">${link2}</a></div>
                <div class="tags">${tags}</div>
                <div class="yt-link"><a href="${ytlink}">Youtube Reference</a></div>
            </p>
          </div>
        </div>
      </div><br><br>`;
  quesContainer.insertAdjacentHTML('beforeend', html);
};

const getData = async function() {
  const data = await fetch("https://test-data-gules.vercel.app/data.json");
  const res = await data.json();
  const finalData = res.data;
  finalData.forEach(element => {
    element.ques.forEach(function(el) {
      //console.log(element.title);
      renderData(element.title, el.title, el.tags, el.p1_link, el.p2_link, el.yt_link);
    })
  });
}


//renderData();

getData();

const btns = document.querySelectorAll(".btn");
console.log(btns);
btns.forEach(function(element) {
  element.addEventListener("click", function() {
    console.log("clicked");
    element.classList.toggle("active");
    var panel = element.nextElementSibling;
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  });
})
<div class="container"></div>

1

There are 1 answers

2
mplungjan On

Your event handlers are assigned in a place where the elements are not (yet) available.

You need to delegate. Here is a way to so do.

I also took the time to simplify the render

'use strict';
const quesContainer = document.querySelector('.container');



const renderData = (mainTitle, quesTitle, tags, link1, link2, ytlink) => `<button class="btn">Show</button>
      <div class="panel" hidden>
        <div class="topic">
          <div class="question">
            <p>
                <div class="mainTitle"><h1>${mainTitle}</h1></div>
                <div class="ques-title">${quesTitle}</div>
                <div class="link-1"><a href="${link1}">${link1}</a></div>
                <div class="link-2"><a href="${link2}">${link2}</a></div>
                <div class="tags">${tags}</div>
                <div class="yt-link"><a href="${ytlink}">Youtube Reference</a></div>
            </p>
          </div>
        </div>
      </div><br><br>`;



const getData = async function() {
  const data = await fetch("https://test-data-gules.vercel.app/data.json");
  const res = await data.json();
  const finalData = res.data;
  //  console.log(finalData)
  quesContainer.innerHTML = finalData
    .map(element => `<div class="q">${element.ques
      .map(el => renderData(element.title, el.title, el.tags, el.p1_link, el.p2_link, el.yt_link))
      .join('')}</div>`)
    .join('');

}


quesContainer.addEventListener("click", (e) => {
  const element = e.target.closest('button');
  element.classList.toggle("active");
  quesContainer.querySelectorAll('.btn').forEach(btn => {
    btn.nextElementSibling.hidden = !btn.matches('.active');
  });
});
getData();
.active {
  color: green;
}
<div class="container"></div>