javascripthtmlcsse-commercerating

Adding rating star in JavaScript e-commerce website


I’m having trouble fixing a JavaScript issue. I’ll share my HTML and JavaScript code. Here’s what I’m trying to achieve:

Before clicking any star, star-value.textContent should be ‘-’.

When a star is clicked, it should change to that star’s value (e.g., poor, average, good…).

But if the same star is clicked again, it should reset star-value.textContent back to ‘-’.

The problem is: clicking the same star again doesn’t reset it to ‘-’. It just stays at the same value.

Code:

const stars = document.querySelectorAll(".stars");
let selectedStars = 0;

stars.forEach(star => {
  star.addEventListener("mouseover", () => {
    const nthStar = parseInt(star.id.split("-")[1]);

    stars.forEach((s, index) => {
      s.textContent = (index < nthStar) ? "★" : "☆";
    });
  });

  star.addEventListener("mouseleave", () => {
    stars.forEach((s, index) => {
      s.textContent = (index < selectedStars) ? "★" : "☆";
    });
  });

  star.addEventListener("click", () => {
    const nthStar = parseInt(star.id.split("-")[1]);
    if (nthStar === selectedStars) {
      selectedStars = 0;
      return;
    } else {
      selectedStars = nthStar;
    }

    stars.forEach((s, index) => {
      s.textContent = (index < selectedStars) ? "★" : "☆";
    });

    valueDetectOfReview(selectedStars);
  });
});


const review = document.querySelector('.star-value');


function valueDetectOfReview(starNumber) {
  switch (starNumber) {
    case 0:
      review.textContent = '-';
      break;
    case 1:
      review.textContent = 'Very Poor';
      break;
    case 2:
      review.textContent = 'Poor';
      break;
    case 3:
      review.textContent = 'Average';
      break;
    case 4:
      review.textContent = 'Good';
      break;
    case 5:
      review.textContent = 'Excellent';
      break;
    default:
      break;
  }
}
<div class="rating">
  <div class="section-header">
    <p>Rating</p>
  </div>
  <div class="section-main">
    <span class="stars" id="star-1">&#9734;</span>
    <span class="stars" id="star-2">&#9734;</span>
    <span class="stars" id="star-3">&#9734;</span>
    <span class="stars" id="star-4">&#9734;</span>
    <span class="stars" id="star-5">&#9734;</span>
  </div>
  <div class="star-value">-</div>
</div>


Solution

  • When you click the selected star, you do selectedStars = 0; return;. That prevents the rest of the event listener from running, so you never reset the text content.

    Get rid of the return statement and it does what you want.

    const stars = document.querySelectorAll(".stars");
    let selectedStars = 0;
    
    stars.forEach(star => {
      star.addEventListener("mouseover", () => {
        const nthStar = parseInt(star.id.split("-")[1]);
    
        stars.forEach((s, index) => {
          s.textContent = (index < nthStar) ? "★" : "☆";
        });
      });
    
      star.addEventListener("mouseleave", () => {
        stars.forEach((s, index) => {
          s.textContent = (index < selectedStars) ? "★" : "☆";
        });
      });
    
      star.addEventListener("click", () => {
        const nthStar = parseInt(star.id.split("-")[1]);
        if (nthStar === selectedStars) {
          selectedStars = 0;
        } else {
          selectedStars = nthStar;
        }
    
        stars.forEach((s, index) => {
          s.textContent = (index < selectedStars) ? "★" : "☆";
        });
    
        valueDetectOfReview(selectedStars);
      });
    });
    
    
    const review = document.querySelector('.star-value');
    
    
    function valueDetectOfReview(starNumber) {
      switch (starNumber) {
        case 0:
          review.textContent = '-';
          break;
        case 1:
          review.textContent = 'Very Poor';
          break;
        case 2:
          review.textContent = 'Poor';
          break;
        case 3:
          review.textContent = 'Average';
          break;
        case 4:
          review.textContent = 'Good';
          break;
        case 5:
          review.textContent = 'Excellent';
          break;
        default:
          break;
      }
    }
    <div class="rating">
      <div class="section-header">
        <p>Rating</p>
      </div>
      <div class="section-main">
        <span class="stars" id="star-1">&#9734;</span>
        <span class="stars" id="star-2">&#9734;</span>
        <span class="stars" id="star-3">&#9734;</span>
        <span class="stars" id="star-4">&#9734;</span>
        <span class="stars" id="star-5">&#9734;</span>
      </div>
      <div class="star-value">-</div>
    </div>