skip to Main Content

I have created a function add element to click event listener. It is supposed to be change img src attribute but at least one element doesnt change src attribute when I add a few new items

the code is like that:

function updateCheckButtons(){
        let checkButtons= document.querySelectorAll(".uncheck");
        checkButtons.forEach(chk=>{
            chk.addEventListener("click",function(){
               let src=chk.getAttribute("src");
               if(src.endsWith("unchecked.png")){
                chk.setAttribute("src","images/checked.png")
               }
               else {
                chk.setAttribute("src","images/unchecked.png")
               }
            })
        })
    }




2

Answers


  1. Chosen as BEST ANSWER

    I solved my problem. Thank you. Instead of calling the addEventFunction for every item when adding them dynamically, which handles both old and new items, I created a function that addresses and adds an event handler only for the last item. This approach resolved the issue. that is the working code

       function updateCheckButtons(){
        let checkButtons= document.querySelectorAll(".uncheck");
        checkButtons[checkButtons.length-1].addEventListener("click",function(){
             let src=  checkButtons[checkButtons.length-1].getAttribute("src");
             if(src=="images/unchecked.png"){
                checkButtons[checkButtons.length-1].setAttribute("src","images/checked.png")
               }
               else {
                checkButtons[checkButtons.length-1].setAttribute("src","images/unchecked.png")
               }
        })
    

  2. If you want to toggle an image from checked/unchecked, I would first name my functions more meaningfully.

    Now, I would store the images in a state array. The unchecked state should be at index 0, and the checked should be at index 1. You can now use modular arithmetic to cycle through the images.

    const imgState = [
      'https://img.icons8.com/?id=19336&format=png', // off
      'https://img.icons8.com/?id=25534&format=png', // on
    ];
    
    enableClickListeners('.uncheck', handleClick);
    
    function handleClick({ target: chk }) {
      const currentIndex = imgState.indexOf(chk.getAttribute('src'));
      chk.setAttribute('src', nextState(imgState, currentIndex));
    }
    
    function nextState(states, currentIndex) {
      return states[(currentIndex + 1) % states.length];
    }
    
    function enableClickListeners(selector, ...eventListeners) {
      document.querySelectorAll(selector).forEach(el => {
        eventListeners.forEach(eventListener => {
          el.addEventListener('click', eventListener);
        });
      })
    }
    
    function disableClickListeners(selector, ...eventListeners) {
      document.querySelectorAll(selector).forEach(el => {
        eventListeners.forEach(eventListener => {
          el.removeEventListener('click', eventListener);
        });
      })
    }
    .uncheck {
      cursor: pointer;
      width: 32px;
      height: 32px;
    }
    <img class="uncheck" src="https://img.icons8.com/?id=25534&format=png"/>
    <img class="uncheck" src="https://img.icons8.com/?id=19336&format=png" />
    <img class="uncheck" src="https://img.icons8.com/?id=19336&format=png" />

    Now, what I would recommend is that you use data attributes + CSS to style the checkboxes. The checkbox should be represented as a <span> or <div>, and the image should be a CSS background image.

    The added benefits of data attributes are:

    • They are more meaningful, manageable, and readable
    • No need to juggle CSS classes around
    • Can get the state through HTML or JS
    enableClickListeners('.uncheck', handleClick);
    
    function handleClick({ target: chk }) {
      const isChecked = chk.dataset.checked === 'true';
      chk.dataset.checked = !isChecked;
    }
    
    function enableClickListeners(selector, ...eventListeners) {
      for (let el of document.querySelectorAll(selector)) {
        for (let eventListener of eventListeners) {
          el.addEventListener('click', eventListener);
        }
      }
    }
    
    function disableClickListeners(selector, ...eventListeners) {
      for (let el of document.querySelectorAll(selector)) {
        for (let eventListener of eventListeners) {
          el.removeEventListener('click', eventListener);
        }
      }
    }
    .uncheck {
      display: inline-block;
      width: 32px;
      height: 32px;
      background: url('https://img.icons8.com/?id=19336&format=png&size=32');
    }
    
    .uncheck[data-checked="true"] {
      background-image: url('https://img.icons8.com/?id=25534&format=png&size=32');
    }
    
    .uncheck:hover {
      cursor: pointer;
    }
    <span class="uncheck" data-checked="true"></span>
    <span class="uncheck"></span>
    <span class="uncheck"></span>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search