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>
Related
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>
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>
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
I want to create rows based on input box blur event. so I have tried the for loop with jquery to append the rows in a table but it will take more time or some time page not respond when loop value reach more than 10000.
$("#place_count").blur(function () {
var row_count = 1;
if ($(this).val() > 1) {
row_count = parseInt($(this).val());
}
var intial_count = $('#route_places_table tr').length;
for (var i = (intial_count + 1); i <= row_count; i++) {
$('#route_places_table tbody').append('<tr><td>' + i + '</td><td>
< input type = "text" class= "place_input" name = "places[]" ></td >
<td>
<span class="add_row_below row_icons">
<i class="fa fa- plus" aria-hidden="true"></i>
</span> <span class="move_row_up row_icons">
<i class="fa fa-arrow-up"></i> </span>
<span class="move_row_down row_icons">
<i class="fa fa-arrow-down" aria-hidden="true"></i>
</span><span class="close_row row_icons">
<i class="fa fa-window-close" aria-hidden="true"></i></span>
</td></tr >'
);
}
});
so how to reduce the delay time? or if any problem with my code please help me to improve the code.
You can try to append only once after the loop has ended, but i strongly suggest to limit the number of rows you append to the page, you don't usually need that many, many dom nodes make the page slow, i suggest you use some king of pagination
var html ='';
for(var i=(intial_count+1);i<=row_count;i++){
html+= '<tr><td>'+i+'</td><td>
<input type="text" class="place_input" name="places[]"></td>
<td>
<span class="add_row_below row_icons">
<i class="fa fa- plus" aria-hidden="true"></i>
</span> <span class="move_row_up row_icons">
<i class="fa fa-arrow-up"></i> </span>
<span class="move_row_down row_icons">
<i class="fa fa-arrow-down" aria-hidden="true"></i>
</span><span class="close_row row_icons">
<i class="fa fa-window-close" aria-hidden="true"></i></span>
</td></tr>';
}
$('#route_places_table tbody').append(html);
Instead of appending each row one by one, append the whole template at once. This way the time should get reduced.
var rows = [];
for (var i = (intial_count + 1); i <= row_count; i++) {
rows.push('<tr><td>'+i+'</td><td>
<input type="text" class="place_input" name="places[]"></td>
<td>
<span class="add_row_below row_icons">
<i class="fa fa- plus" aria-hidden="true"></i>
</span> <span class="move_row_up row_icons">
<i class="fa fa-arrow-up"></i> </span>
<span class="move_row_down row_icons">
<i class="fa fa-arrow-down" aria-hidden="true"></i>
</span><span class="close_row row_icons">
<i class="fa fa-window-close" aria-hidden="true"></i></span>
</td></tr>');
}
$('#route_places_table tbody').append(rows.join(''));
I have five elements and want something to happend when I click one of them. My code works fine when clicking for first time, but the event never hits on second click. Any idea why?
$("#ratingModal").find(".star.clickable").on("click", function () {
console.log("click");
var $wrap = $(this).closest(".stars");
var count = parseInt($(this).data("star"));
$.each($wrap.find(".star"), function ($index, $itm) {
let current = parseInt($($itm).data("star"));
$($itm).removeClass("fas");
$($itm).removeClass("far");
console.log(current);
if (current <= count) {
$($itm).addClass("fas");
console.log("fas");
}
else {
$($itm).addClass("far");
console.log("far");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="ratingModal">
<div class="body">
<div class="score-wrap">
<span class="label">Score: </span>
<div class="stars">
<i class="fas fa-star clickable star star-1" title="1" data-star="1"></i>
<i class="far fa-star clickable star star-2" title="2" data-star="2"></i>
<i class="far fa-star clickable star star-3" title="3" data-star="3"></i>
<i class="far fa-star clickable star star-4" title="4" data-star="4"></i>
<i class="far fa-star clickable star star-5" title="5" data-star="5"></i>
</div>
</div>
</div>
</div>
Try Using off().on('...') function
$("#ratingModal").find(".star.clickable").off().on("click", function () {
console.log("click");
var $wrap = $(this).closest(".stars");
var count = parseInt($(this).data("star"));
$.each($wrap.find(".star"), function ($index, $itm) {
let current = parseInt($($itm).data("star"));
$($itm).removeClass("fas");
$($itm).removeClass("far");
console.log(current);
if (current <= count) {
$($itm).addClass("fas");
console.log("fas");
}
else {
$($itm).addClass("far");
console.log("far");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="ratingModal">
<div class="body">
<div class="score-wrap">
<span class="label">Score: </span>
<div class="stars">
<i class="fas fa-star clickable star star-1" title="1" data-star="1"></i>
<i class="far fa-star clickable star star-2" title="2" data-star="2"></i>
<i class="far fa-star clickable star star-3" title="3" data-star="3"></i>
<i class="far fa-star clickable star star-4" title="4" data-star="4"></i>
<i class="far fa-star clickable star star-5" title="5" data-star="5"></i>
</div>
</div>
</div>
</div>