Reinitialise array of click events for links after page has dynamically changed

38 views Asked by At

I am trying to make a simple site and convert it to an SPA using vanilla javascript.

I want to target all of my hyperlinks which start with an '/' as these are internal to my site.

Works fine for pages loaded in the DOM initially from the server. But if I dynamically add more links to the page that contain the same property I need a way to recalculate my list of internal links. This is a simplified version of a slightly more complex iteration.

Snippet below, but I also made a codepen: https://codepen.io/lharby/pen/OJqoRpx

  const trigger = document.querySelector(".add-template");
  const wrapper = document.querySelector(".wrapper");
  const links = document.querySelectorAll("a");
  const internal = [...links]?.filter((item) => item.getAttribute("href")?.startsWith("/"));
  internal.forEach((item) => item.classList.add("internal"));

  const getLinks = () => {
    const links = document.querySelectorAll("a");
    const internal = [...links]?.filter((item) => item.getAttribute("href")?.startsWith("/"));
    internal.forEach((item) => item.classList.add("internal"));
    console.log(internal, internal.length);
  };

  const recalculateInternal = () => {
    getLinks();
    internal.forEach((item) => {
      item.addEventListener("click", (event) => {
        event.preventDefault();
        console.log(event.target);
      });
    });
  };

  recalculateInternal();

  const template = `
    <ul>
        <li><a href="/link4">Link 4</a></li>
        <li><a href="/link5">Link 5</a></li>
        <li><a href="#">Link 6</a></li>
        <li><a href="https://some-site.com">Link 7</a></li>
    </ul>
    `;

  trigger.addEventListener("click", () => {
    wrapper.insertAdjacentHTML("beforeend", template);
    recalculateInternal();
  });
 <nav>
      <ul>
        <li><a href="/link1">Link 1</a></li>
        <li><a href="#">Link 2</a></li>
        <li><a href="/another-link">Link 3</a></li>
      </ul>
    </nav>
    <section>
      <p>Heading</p>
      <div>This is some article text with an <a href="/article-link">internal</a> link</div>
    </section>
    <section>
      <div>
        <p>Section heading</p>
        <p>Another article with an <a href="https://google.co.uk">external</a> link</p>
      </div>
    </section>
    <button class="add-template">Add template</button>
    <div class="wrapper"></div>

When I trigger the event, the links dynamically added to the array of internal links are reflected in the console. But they do not appear to have the click event added dynamically. My guess is each time new dynamic links are added I need someway to remove them from all items with a forEach loop and add them again with the new links in the DOM.

enter image description here

I have researched adding and removing event handlers for an array of elements after using a forEach loop and I don't understand how to get anything to work. removeEventListener requires a listener name.

I tried to add internal.forEach((item) => item.replaceWith(item.cloneNode(true)));

Inside this function:

  trigger.addEventListener("click", () => {
    wrapper.insertAdjacentHTML("beforeend", template);
    internal.forEach((item) => item.replaceWith(item.cloneNode(true)));
    recalculateInternal();
  });

From what I understand that should remove all event handlers from those items. And they should be reinitialised again inside my recalculateInternal function.

For reference

Javascript/DOM: How to remove all event listeners of a DOM object?

removeEventListener without knowing the function

0

There are 0 answers