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">☆</span>
<span class="stars" id="star-2">☆</span>
<span class="stars" id="star-3">☆</span>
<span class="stars" id="star-4">☆</span>
<span class="stars" id="star-5">☆</span>
</div>
<div class="star-value">-</div>
</div>
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">☆</span>
<span class="stars" id="star-2">☆</span>
<span class="stars" id="star-3">☆</span>
<span class="stars" id="star-4">☆</span>
<span class="stars" id="star-5">☆</span>
</div>
<div class="star-value">-</div>
</div>