skip to Main Content

When you click on a category, its name should turn red. But this only works for pre-rendered categories, and if you add a new one (it works with the input and ‘add btn’), the event handler does not work, nothing happens with the text

// * Adding active class for the cat
const addActiveClass = (elem) => {
  elem.classList.add("active");
};
// ! Removing active class
const removeActiveClass = (catArr) => {
  Array.from(catArr).forEach((elem) => {
    elem.classList.remove("active");
  });
};

Array.from(document.getElementsByClassName("categories__text")).forEach(
  (elem) => {
    elem.addEventListener("click", (e) => {
      removeActiveClass(document.getElementsByClassName
      ("categories__text"));
      addActiveClass(e.target);
    });
  }
);
console.log(Array.from(document.getElementsByClassName("categories__text")));
<ul class="categories__list">
  <li class="categories__item">
    <p class="categories__text active">All</p>
  </li>
</ul>

2

Answers


  1. Your issue stems from dynamically added elements not having the same event listeners as the ones initially present. The solution involves using event delegation, where you attach the event listener to a parent element and then verify if the clicked element matches your requirements. look here:

    // Adding and removing active class
    const toggleActiveClass = (elem) => {
      Array.from(document.getElementsByClassName("categories__text")).forEach((el) => {
        el.classList.remove("active");
      });
      elem.classList.add("active");
    };
    
    // Here Goes Event delegation
    document.querySelector('.categories__list').addEventListener('click', (e) => {
      if (e.target && e.target.matches(".categories__text")) {
        toggleActiveClass(e.target);
      }
    });
    

    This way, even elements added later will have the click functionality because the event listener is on the parent, not the individual elements.

    Hope this helps!

    Login or Signup to reply.
    • Watch for click on the UL container
    • e.target is the clicked element. Use e.target.closest() to get the clicked .categories__text if any.
    • add the class, you don’t need a separate function for that, seems an overkill
    document.querySelector('.categories__list')
      .addEventListener('click', e => e.target.closest('.categories__text')?.classList.add('active'));
    
    const addCategory = text => $list.insertAdjacentHTML('beforeend', `
      <li class="categories__item">
        <p class="categories__text">${text}</p>
      </li>
    `);
    .active{
      color:red;
    }
    <ul id="$list" class="categories__list">
      <li class="categories__item">
        <p class="categories__text">All</p>
      </li>
    </ul>
    <input id="$input">
    <button onclick="addCategory($input.value)">Add category</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search