Skip to content
Advertisement

Looping through a DOM element causing all equal elements to be affected

I have a basic Javascript local implementation of a like button and a number that increments every time the button is clicked. The section that contains the like button and the number is rendered by EJS.

HTML

<section id="post-section">

   <%  posts.forEach(function(post) { %>

   <article class="post-container">
       <div class="post-title-container">
           <a href="/post/<%=post.title%>"><%=post.title%></a>
       </div>
       <div class="post-card-container">
           <img class="post-user-image" src="/img/user.png" alt="Imagem do utilizador">
           <p class="post-user-name"><%=post.name%></p>
           <% if (post.content.length > 100) { %>
           <span class="post-body"><%=post.content.substring(0, 100) + " ..."%></span>
           <% } else { %>
                   <span class="post-body"><%=post.content%></span>
           <% } %>
           <span class="post-date">
               <%=post.date%>
           </span>
           <span class="post-like">
               <i class="far fa-heart"></i>
           </span>
           <p class="post-like--count">
               0
           </p>
       </div>
   </article>
   <hr>
   
   <% }); %>
   
</section>

JavaScript

window.onload = function () {
    postLikeCount();
}

function postLikeCount() {
    let likeCount = document.querySelectorAll('.post-like--count');
    let postLikeButtons = document.querySelectorAll('.post-like .far.fa-heart');

    postLikeButtons.forEach(function (postLikeButton) {
        postLikeButton.addEventListener('click', function () {
            postLikeButton.classList.toggle('fas');
            
            likeCount.forEach(function (like) {

                let number = like.textContent;
                
                if (postLikeButton.classList.contains('fas')) {
                    number++;
                    like.textContent = number;
                }
                else {
                    number--;
                    like.textContent = number;
                }
            });
        });
    });
}

My issue is, the number increments correctly when the ‘click’ event is fired, however, it doesn’t only increment on the button that was clicked, if I have multiple posts (as seen in the HTML), it will also increment the number on those buttons.

While debugging, the behavior seems correct. likeCount returns me a NodeList with the size of whatever is the amount of buttons on that page, and when looping, like also gives correct behavior as it grabs a single element, yet, every element gets incremented.

Advertisement

Answer

I think you have too much nesting in your code and your selector do not target a specific element but all the ones having the same classes.

You could simplify this way:

function postLikeCount() {
  document
    .querySelectorAll(".post-like .far.fa-heart")
    .forEach(function (postLikeButton) {
      postLikeButton.addEventListener('click', function () {
        // this is the clicked element
        this.classList.toggle("fas");
        // read its sibling count
        let number = this.parentNode.nextElementSibling.innerText;
        if (this.classList.contains("fas")) {
          number++;
          this.parentNode.nextElementSibling.innerText = number;
        } else {
          number--;
          this.parentNode.nextElementSibling.innerText = number;
        }
    });
  });
}
  
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement