I want to create a responsive star rating in javascript - javascript

This is my HTML
<div id="starRatings">
<span class="fa fa-star checked"></span>
<span class="fa fa-star "></span>
<span class="fa fa-star "></span>
<span class="fa fa-star "></span>
<span class="fa fa-star "></span>
This is my Javascript
const starRating = $("#starRatings").children();
for (let i = 0; i < starRating.length; i++) {
starRating[i].addEventListener("mouseover", function() {
for (let j = 1; j <= starRating.length; j++) {
$(starRating[j]).removeClass("checked");
}
for (let j = 1; j> i; j--) {
$(starRating[j]).addClass("checked");
console.log(starRating[j])
}
});
starRating[i].addEventListener("mouseleave", function() {
for (let j = 1; j <= starRating.length; j++) {
$(starRating[j]).addClass("checked");
console.log(j)
}
for (let j = 1; j> i; j--) {
$(starRating[j]).removeClass("checked");
console.log(j)
}
});
starRating[i].addEventListener("click", function() {
for (let j = 1; j <= starRating.length; j++) {
$(starRating[j]).addClass("checked");
}
for (let j = 1; j> i; j--) {
$(starRating[j]).removeClass("checked");
}
});
}
The class checked simply gives the stars an orange colour and I want one to be orange at all times. I want the others to turn orange on mouse enter and back to grey on mouse leave AND when the user actually wants to click on a number of stars, they remain orange, even after mouse leave, for this im guessing I need an if statement somewhere.
I realise it should be simple and I've got wayyy too many for loops, but im losing my mind!
Can anyone help?

I can offer you an example with jquery
https://jsfiddle.net/mp4oze3f/
CSS
.et-app-sr {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important
}
.et-app-rating-stars {
height: 4em;
display: flex
}
.et-app-rating-star {
background: none;
border: none;
box-shadow: none;
font-size: 3.4em;
cursor: pointer;
}
.et-app-rating-star .selected {
display: none;
color: #edff71
}
.et-app-rating-star.select i, .et-app-rating-star.highlight i {
display: none
}
.et-app-rating-star.select .selected, .et-app-rating-star.highlight .selected {
display: block
}
.et-app-rating-star:focus {
outline: 1px solid #000
}
JS (jQuery)
$('[data-star]').on('click', function(e) {
e.preventDefault();
$(this).addClass('select');
$(this).prevAll('[data-star]').addClass('select');
$(this).nextAll('[data-star]').removeClass('select');
$(this).parent().find('input').val($(this).data('star'));
});
$('[data-star]').on('mouseover', function(e) {
e.preventDefault();
$(this).addClass('highlight');
$(this).prevAll('[data-star]').addClass('highlight');
$(this).nextAll('[data-star]').removeClass('highlight');
});
$('[data-star]').on('mouseout', function(e) {
e.preventDefault();
$(this).removeClass('highlight');
$(this).prevAll('[data-star]').removeClass('highlight');
});
HTML
<div class="et-app-rating-stars">
<input type="hidden">
<button class="et-app-rating-star" data-star="1">
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star selected" aria-hidden="true"></i>
<span class="et-app-sr">Rating: 1 star</span>
</button>
<button class="et-app-rating-star" data-star="2">
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star selected" aria-hidden="true"></i>
<span class="et-app-sr">Rating: 2 star</span>
</button>
<button class="et-app-rating-star" data-star="3">
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star selected" aria-hidden="true"></i>
<span class="et-app-sr">Rating: 3 star</span>
</button>
<button class="et-app-rating-star" data-star="4">
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star selected" aria-hidden="true"></i>
<span class="et-app-sr">Rating: 4 star</span>
</button>
<button class="et-app-rating-star" data-star="5">
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star selected" aria-hidden="true"></i>
<span class="et-app-sr">Rating: 5 star</span>
</button>
</div>
I used more than you need, I change icons, you can look at the logic and do something like this

Related

when I try to translate the element through js, it doesn't work

All the elements with class em, needs to be shown once at the time on the basis of the rating.
I made the emoji contaneir as big as the icons, so with overflow hidden only one can be shown.
The problem is that when i try to modify the transform property, it doesn't work.
const starsEl = document.querySelectorAll(".fa-star");
const ratingcEl = document.querySelectorAll(".em");
console.log(ratingcEl)
starsEl.forEach((starsEl, index) => {
starsEl.addEventListener("click", () => {
console.log('click')
updateRating(index);
});
});
function updateRating(index) {
starsEl.forEach((starsEl, idx) => {
if (idx <= index) {
starsEl.classList.add("active");
} else {
starsEl.classList.remove("active");
}
});
ratingcEl.forEach((ratingcEl) => {
console.log(index)
ratingcEl.style.transform = `translateX(- ${ 50 * index}px)`;
});
}
.emoji-container {
position: absolute;
top: 20%;
left: 50%;
transform: translateX(-50%);
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
overflow: hidden;
}
.emoji-container i {
margin: 1px;
transform: translateX(-200px);
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<body>
<div class="feedback-container">
<div class="emoji-container">
<i class="em fa-regular fa-face-angry fa-3x"></i>
<i class="em fa-regular fa-face-frown fa-3x"></i>
<i class="em fa-regular fa-face-meh fa-3x"></i>
<i class="em fa-regular fa-face-smile fa-3x"></i>
<i class="em fa-regular fa-face-laugh fa-3x"></i>
</div>
<div class="rating-container">
<i class="fa-solid fa-star fa-2x "></i>
<i class="fa-solid fa-star fa-2x "></i>
<i class="fa-solid fa-star fa-2x "></i>
<i class="fa-solid fa-star fa-2x "></i>
<i class="fa-solid fa-star fa-2x "></i>
</div>
</div>
<script src="emojii.js"></script>
</body>
I want the icons to translate left, in order to show the right face for the rating.
This can be greatly simplified. Removed all position/transform/display rules from CSS. They bring unnecessary complexity for such a simple task. Also added gold color for stars with active class and started with 5 active star.
const starsEl = document.querySelectorAll(".fa-star");
const emoji = document.getElementById("emoji");
const emojis = ["angry", "frown", "meh", "smile", "laugh"]; // just the changing parts
starsEl.forEach((starsEl, index) => {
starsEl.addEventListener("click", () => {
updateRating(index);
});
});
function updateRating(index) {
starsEl.forEach((starsEl, idx) => {
if (idx <= index) {
starsEl.classList.add("active");
} else {
starsEl.classList.remove("active");
}
});
emoji.classList = ["em fa-regular fa-face-" + emojis[index] + " fa-3x"];
}
#rating-container > .active {
color: gold;
}
#emoji-container {
text-align: center;
margin-top: 2rem;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<body>
<div id="feedback-container">
<div id="rating-container">
<i class="fa-solid fa-star fa-2x active"></i>
<i class="fa-solid fa-star fa-2x active"></i>
<i class="fa-solid fa-star fa-2x active"></i>
<i class="fa-solid fa-star fa-2x active"></i>
<i class="fa-solid fa-star fa-2x active"></i>
</div>
<div id="emoji-container">
<i id="emoji" class="em fa-regular fa-face-laugh fa-3x"></i>
</div>
</div>
<script src="emojii.js"></script>
</body>

How to toggle between classes using jquery

I have a rating star in my page, and I'm trying to toggle back and forth between "fa fa-star" class and "fa fa-star checked" class I have read about this here: Javascript/Jquery to change class onclick?
And this is my implementation (it didn't work)
$('.fa fa-star').click(function() { $(this).toggleClass('fa fa-star'); $(this).toggleClass('fa fa-star checked'); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<span onclick="rating" class="fa fa-star"></span>
<span onclick="rating" class="fa fa-star checked"></span>
<span onclick="rating" class="fa fa-star checked"></span>
<span onclick="rating" class="fa fa-star checked"></span>
<span onclick="rating" class="fa fa-star"></span>
</div>
You simply need to toggle the checked class for a simplified rating.
$('.stars i').click(function() {
$('.stars i.checked').removeClass('checked');
for (let i = 0; i < $(this).index() + 2; i++) {
$('.stars i:nth-of-type(' + i + ')').addClass('checked');
}
});
.stars i {
color: #ccc;
cursor: pointer;
}
.stars i.checked {
color: #dfd022;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div class="stars">
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
</div>
If you need the option of being able to convert stars back to '0', you can use the following option:
$('.stars i').click(function() {
if($(this).index() === 0 && $('.stars i.checked').length === 1){
$('.stars i.checked').removeClass('checked');
} else {
$('.stars i.checked').removeClass('checked');
for (let i = 0; i < $(this).index() + 2; i++) {
$('.stars i:nth-of-type(' + i + ')').addClass('checked');
}
}
});
.stars i {
color: #ccc;
cursor: pointer;
}
.stars i.checked {
color: #dfd022;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div class="stars">
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
</div>
maybe that...
document.querySelectorAll('i.fa-star')
.forEach( (star,indx,arr) =>
{
star.onclick =_=>
{
let chk = star.classList.toggle('checked')
arr.forEach((s,i) =>
s.classList.toggle('checked', i<indx ? true: i===indx ? chk : false))
}
})
body {
background : darkslategrey;
font-size : 24px;
}
i.fa-solid.fa-star {
color : lightgray;
cursor : pointer;
}
i.fa-solid.fa-star.checked {
color : gold;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
</div>
If you want the same as prettyInPink's answer :
document.querySelectorAll('i.fa-star')
.forEach( (star,indx,arr) => star.onclick =_=>
arr.forEach((s,i) => s.classList.toggle('checked', i<=indx )))
body {
background : darkslategrey;
font-size : 24px;
}
i.fa-solid.fa-star {
color : lightgray;
cursor : pointer;
}
i.fa-solid.fa-star.checked {
color : gold;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
<i class="fa-solid fa-star"></i>
</div>

Using the position property use the icon

I am totally new to the web development. Here I have this icon:
I am using Font Awesome, and there is no icon that matches that, so I am trying to make a icon using the following way:
<td>
<div style={positionOf}>
<i class="fa fa-envelope"></i>
<i class="fa fa-check-circle" aria-hidden="true"></i>
</div>
</td>
{
top: 0.3em;
position: absolute;
}
Here I am trying position : absolute to the second icon and relative to the first one.
So, but this is not working.
Can any one help me with this ?
Thanks.
To make sure your code is working you have to give some values to the icons. By giving some values to the icon they will be indented. Use the following Properties.
top : 14px;
left : 15px;
Try with
<div>
<span class="icon-outer">
<i class="fa fa-envelope"></i>
<i class="fa fa-check-circle" aria-hidden="true"></i>
</span>
</div>
.icon-outer{
position:relative;
}
.fa-envelope{
font-size:30px;
color:green;
}
.fa-check-circle{
position:absolute;
right:5px;
bottom:0px;
color:#fff;
}
https://jsfiddle.net/lalji1051/wzvaqspr/7/
You can do this consider the classes that Font Awesome provides (https://fontawesome.com/how-to-use/on-the-web/styling/)
.fa-check-circle,
.fa-envelope {
color: green;
}
.fa-circle {
color: #fff;
}
<script data-search-pseudo-elements src="https://use.fontawesome.com/releases/v5.8.1/js/all.js"></script>
<span>
<i class="fa fa-envelope" data-fa-transform="grow-15"></i>
<span class="fa-stack ">
<i class="fas fa-circle fa-stack-1x" data-fa-transform="left-20 down-18"></i>
<i class="far fa-check-circle fa-stack-1x" data-fa-transform="left-20 down-18"></i>
</span>
</span>

Multiple fa-heart like count increment and decrement

I need to increment the count of a fa-heart value on click and decrement on the second click.
Problem is I have multiple fa-heart in the same page, so unable to increment/decrement on the clicked fa-heart.
Here is my fiddle below
https://jsfiddle.net/mehbub/d9e2qotg/1/
(function() {
const heart = document.getElementById('heart');
heart.addEventListener('click', function() {
heart.classList.toggle('red');
});
})();
$(document).on('click', ".notliked", function() {
var $this = $(this);
$this.removeClass('notliked');
$this.addClass('liked')
$count = $('.likes-count');
$count.text(function(idx, txt) {
return (+txt == 0) ? 0 : (+txt - 1);
heart.classList.toggle('grey');
});
});
$(document).on('click', ".liked", function() {
var $this = $(this);
$this.removeClass('liked');
$this.addClass('notliked');
$count = $('.likes-count');
$count.text(function(idx, txt) {
return +txt + 1;
heart.classList.toggle('red');
});
});
$count.text(function(idx, txt) {
// convert text to number and increment by one
return +txt + 1;
});
#heart {
color: grey;
font-size: 20px;
}
#heart.red {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<p>
robert stephen</p><i class="fa fa-heart liked heart" id="heart" value="1" ></i>
<span class="likes-count"> 100 </span><br>
<p>
James Camroon</p>
<i class="fa fa-heart liked heart" id="heart" value="1" ></i>
<span class="likes-count"> 101 </span><br>
<p>
John Wick</p>
<i class="fa fa-heart liked heart" id="heart" value="1" ></i>
<span class="likes-count"> 37 </span><br>
<p>
James Bond</p>
<i class="fa fa-heart liked heart" id="heart" value="1" ></i>
<span class="likes-count"> 22 </span><br>
<p>
Avengers</p>
<i class="fa fa-heart liked heart" id="heart" value="1" ></i>
<span class="likes-count"> 90 </span>
I need individual click increment/decrement for each fa-heart to color change to red if increment, or grey if the decrement
Thanks
You should remove the duplicate id heart or just remove it since you've already a class heart then attach the click to this common class and toggle the classes liked/notliked, you could use those classes as a rules in your CSS so no need for red/grey classes, something like :
$(document).on('click', ".heart", function() {
var count = $(this).next('span');
$(this).toggleClass('notliked liked');
if ($(this).hasClass('liked')) {
count.text(Number(count.text()) + 1);
} else {
count.text(Number(count.text()) - 1);
}
});
.heart.notliked {
color: grey;
font-size: 20px;
}
.heart.liked {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<p>robert stephen</p>
<i class="fa fa-heart liked heart" value="1"></i>
<span class="likes-count"> 100 </span><br>
<p>James Camroon</p>
<i class="fa fa-heart liked heart" value="1"></i>
<span class="likes-count"> 101 </span><br>
<p>John Wick</p>
<i class="fa fa-heart liked heart" value="1"></i>
<span class="likes-count"> 37 </span><br>
<p>James Bond</p>
<i class="fa fa-heart liked heart" value="1"></i>
<span class="likes-count"> 22 </span><br>
<p>Avengers</p>
<i class="fa fa-heart liked heart" value="1"></i>
<span class="likes-count"> 90 </span>

How can I create a marking an answer as accepted one system?

Explanation: I'm trying to make an accepted-answer system and there are three cases:
marking a new answer as accepted one (there is no accepted answer already)
undo a accepted answer
switching from one answer to another one
Here is my code:
$("body").on('click', '.fa-check', function(e) {
// send a request by ajax and if it is successful then
if( this.attr('color') == '#44b449' ){ // undo
this.css({"color":"#aaa"}); // set gry color to marked icon
} else { // switchin or marking a new one
$('.fa-check').css({"color":"#aaa"}); // set gray color to all icons
this.css({"color":"#44b449"}); // set green color to marked icon
}
});
.fa-check{
color:#aaa;
cursor: pointer;
}
.fa-check:hover{
color: #999;
}
<script src="https://use.fontawesome.com/9e9ad91d21.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>answer1</p>
<i class="fa fa-check" aria-hidden="true"></i>
<hr>
<p>answer2</p>
<i class="fa fa-check" aria-hidden="true" style="color: #44b449;"></i>
<hr>
<p>answer3</p>
<i class="fa fa-check" aria-hidden="true"></i>
But as you see my code doesn't work. How can I fix it?
Note: The whole of my question is about coloring.
Firstly your code is throwing errors as you're calling jQuery methods on this when it refers to a DOMElement, not a jQuery object.
To fix your issues you can simplify your logic by using classes instead of applying inline CSS styling. This allows you to simply toggle the class on click of the .fa-check element. Try this:
$("body").on('click', '.fa-check', function(e) {
// send a request by ajax and if it is successful then
$('.fa-check').not(this).removeClass('checked');
$(this).toggleClass('checked');
});
.fa-check {
color: #aaa;
cursor: pointer;
}
.fa-check.checked {
color: #44b449;
}
<script src="https://use.fontawesome.com/9e9ad91d21.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>answer1</p>
<i class="fa fa-check" aria-hidden="true"></i>
<hr>
<p>answer2</p>
<i class="fa fa-check checked" aria-hidden="true"></i>
<hr>
<p>answer3</p>
<i class="fa fa-check" aria-hidden="true"></i>
Use this method
function click_div(div) {
$("#main_div div .fa-check").css("color"," #aaa");
$("#"+div+" .fa-check").css("color"," #44b449");
}
#div_1,#div_2,#div_3
{
width:100%;
height:100px;
}
.fa-check{
color:#aaa;
cursor: pointer;
}
.fa-check:hover{
color: #999;
}
<html>
<head>
<script src="https://use.fontawesome.com/9e9ad91d21.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<div id="main_div">
<div id="div1" onclick="click_div('div1')">
<p>answer1</p>
<i class="fa fa-check" aria-hidden="true"></i>
</div>
<hr>
<div id="div2" onclick="click_div('div2')">
<p>answer2</p>
<i class="fa fa-check" aria-hidden="true" style="color: #44b449;"></i>
</div>
<hr>
<div id="div3" onclick="click_div('div3')">
<p>answer3</p>
<i class="fa fa-check" aria-hidden="true"></i>
</div>
</div>
</html>

Categories