'click' event only fires on first click and not second - javascript

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>

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>

Star Rating mouse click when hovering over stars

I'm trying to have a mouse icon show up when I hover over the stars in this script using Bootstrap 4.
This is the form.
<div class="form-group">
<h4>Rate this product</h4>
<i class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
<i class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
<i class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
<i class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
<i class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
<input type="hidden" class="form-control" id="rating" name="rating" value="1">
<input type="hidden" class="form-control" id="product_id" name="product_id" value="<?php echo $_GET['id']; ?>">
<input type="hidden" name="action" value="saveRating">
</div>
And here is the Javascript
$( ".rateButton" ).click(function() {
if($(this).hasClass('star-grey')) {
$(this).removeClass('star-grey').addClass('star-highlight star-selected');
$(this).prevAll('.rateButton').removeClass('star-grey').addClass('star-highlight star-selected');
$(this).nextAll('.rateButton').removeClass('star-highlight star-selected').addClass('star-grey');
} else {
$(this).nextAll('.rateButton').removeClass('star-highlight star-selected').addClass('star-grey');
}
$("#rating").val($('.star-selected').length); //count the num of star selected
});
This is how I want it to look https://imgur.com/a/sTkSQR2
I'm trying to have a mouse icon show up when I hover over the stars in
this script using Bootstrap 4
Showing mouse cursor to look like pointed hand (as in image) can be done using below css.
.rateButton {
cursor: pointer
}
Bootstrap way of doing it
Add role="button", then a cursor turns to hand. Bootstrap reference
Reboot includes an enhancement for role="button" to change the default
cursor to pointer. Add this attribute to elements to help indicate
elements are interactive. This role isn’t necessary for
elements, which get their own cursor change.
Your code will look like
<i role="button" class="fa fa-star fa-lg star-grey rateButton" aria-hidden="true"></i>
Example
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<i role="button"> I am an i tag, hovering me should change the cursor to a hand</i>
<br />
<br />
<i> I am an i tag, but I dont have role="button" hovering me WILL NOT change cursor to a hand</i>
I prefer the first method if you don't want to edit the html

open div on click of image

I have a very simple module to develop. On click of an image I need to open up a div element that I have created.I have attached my HTML and javascript file.When I am loading the page the div wont be coming because I have given style="display:none
myfunction() {
document.getElementById('Chatbot').style.visibility = "visible";
}
<body>
<a href="#Chatbot" id="chat" onclick="myfunction()">
<img src="sticky.png" style="width:50px;height:50px">
</a>
<div id="Chatbot" style="display:none">
<div id="header">
Legal Genie
<div class="icons">
<i class="fa fa-question-circle" aria-hidden="true"></i>
<i class="fa fa-refresh" aria-hidden="true"></i>
<i class="fa fa-times" aria-hidden="true"></i>
</div>
</div>
<div><textarea rows="3" cols="20">Press enter to send your message</textarea>
</div>
</div>
</body>
document.getElementById('Chatbot').style.display = "block";
function myfunction() {
document.getElementById('Chatbot').style.display = "block";
}
<body>
<a href="#Chatbot" id="chat" onclick="myfunction()">
Some Image
</a>
<div id="Chatbot" style="display:none">
<div id="header">
Legal Genie
<div class="icons">
<i class="fa fa-question-circle" aria-hidden="true"></i>
<i class="fa fa-refresh" aria-hidden="true"></i>
<i class="fa fa-times" aria-hidden="true"></i>
</div>
</div>
<div><textarea rows="3" cols="20">Press enter to send your message</textarea>
</div>
</div>
</body>
Avoid using inline scripts and also avoid capitalising the first letter of your ID or class name.
Just add an event listener to your #chat anchor link that loads a function which sets the css display property of your div to block on click like this:
/* JavaScript */
var chat = document.getElementById("chat");
var div = document.getElementById('chatbot');
function showDiv(){
div.style.display = "block";
}
chat.addEventListener("click", showDiv);
/* CSS */
a {text-decoration: none; padding: 5px; background-color: green; color: white;}
#chatbot {display: none;}
<!-- HTML -->
<a type="button" href="#Chatbot" id="chat">Open Div</a>
<hr>
<div id="chatbot">
<div id="header">
Legal Genie
<div class="icons">
<i class="fa fa-question-circle" aria-hidden="true"></i>
<i class="fa fa-refresh" aria-hidden="true"></i>
<i class="fa fa-times" aria-hidden="true"></i>
</div>
</div>
<div><textarea rows="3" cols="20">Press enter to send your message</textarea>
</div>
It can be a simple way
<script>
$( document ).ready(function() {
$('#chat').click( function(){
if ( $('#Chatbot').hasClass('active') ) {
$('#Chatbot').removeClass('active');
} else {
$('#Chatbot').addClass('active');
}
});
});
</script>
Add lil css
<style>
.active {
display:block!important;
}
</style>
Your HTML
<body>
<div id="chat">
Some Image
</div>
<div id="Chatbot" style="display:none">
<div id="header">
Legal Genie
<div class="icons">
<i class="fa fa-question-circle" aria-hidden="true"></i>
<i class="fa fa-refresh" aria-hidden="true"></i>
<i class="fa fa-times" aria-hidden="true"></i>
</div>
</div>
<div><textarea rows="3" cols="20">Press enter to send your message</textarea>
</div>
</div>
</body>

Text swap from radio for active button

I have the fa-icon for the selected radio going to the menu-btn, but how do I also take the text from the radio?
$("body").on("click", ".btn-opt", function(event) {
var $el = $(this);
var id = $el.attr("id");
$(this)
.parent()
.parent()
.find("span.selected")
.removeClass("active");
$el.find("span.selected").addClass("active");
$(".menu-btn > i:first")
.removeClass()
.addClass("fa fa-fw fa-" + id);
$(".menu-btn")
.removeClass()
.addClass("menu-btn btn btn-primary fg-" + id);
});
<link href="https://use.fontawesome.com/releases/v5.0.10/css/all.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class="menu-btn btn fg-create"><i class="fa fa-plus fa-fw"></i><i class="arrow fa fa-fw"></i>Menu</div>
<div class="menu">
<div class="btn-opt btn fg-shopping-bag" id="shopping-bag">
<label for="shopbtn"><input id="shopbtn" name="toggler" type="radio"><i class="fa fa-fw fa-shopping-bag"></i> Bag</label>
</div>
<div class="btn-opt btn fg-rocket" id="rocket">
<label for="rocketbtn"><input id="rocketbtn" name="toggler" type="radio"><i class="fa fa-fw fa-rocket"></i> Rocket</label>
</div>
</div>
</div>
If you can wrap the text that needs to be changed in its own element, you can just add one more line to the bottom of your code:
$("body").on("click", ".btn-opt", function(event) {
var $el = $(this);
var id = $el.attr("id");
$(this)
.parent()
.parent()
.find("span.selected")
.removeClass("active");
$el.find("span.selected").addClass("active");
$(".menu-btn > i:first")
.removeClass()
.addClass("fa fa-fw fa-" + id);
$(".menu-btn")
.removeClass()
.addClass("menu-btn btn btn-primary fg-" + id);
// Set the top text to the text of the clicked element
$("span#topText").text($(this).text());
});
<link href="https://use.fontawesome.com/releases/v5.0.10/css/all.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class="menu-btn btn fg-create"><i class="fa fa-plus fa-fw"></i><i class="arrow fa fa-fw"></i>
<!-- Wrap the text to be changed in its own element -->
<span id="topText">Menu</span>
</div>
<div class="menu">
<div class="btn-opt btn fg-shopping-bag" id="shopping-bag">
<label for="shopbtn"><input id="shopbtn" name="toggler" type="radio"><i class="fa fa-fw fa-shopping-bag"></i> Bag</label>
</div>
<div class="btn-opt btn fg-rocket" id="rocket">
<label for="rocketbtn"><input id="rocketbtn" name="toggler" type="radio"><i class="fa fa-fw fa-rocket"></i> Rocket</label>
</div>
</div>
</div>
If you don't like to change your html,
you can use nodeType===3 to filter out all text contents in $(.menu-btn).contents(), then replace it with the value you want.
$("body").on("click", ".btn-opt", function(event) {
var $el = $(this);
var id = $el.attr("id");
$(this)
.parent()
.parent()
.find("span.selected")
.removeClass("active");
$el.find("span.selected").addClass("active");
$(".menu-btn > i:first-child")
.removeClass()
.addClass("fa fa-fw fa-" + id);
// find out all text content (nodeType===3), then replace with yours
//.each is not required, you can change to [0].textContent = 'yourConent' if make sure at least exists one text content.
$(".menu-btn").contents().filter(function() {
return this.nodeType == 3
}).each(function(){
this.textContent = $el.find('label').text();
});
$(".menu-btn")
.removeClass()
.addClass("menu-btn btn btn-primary fg-" + id);
});
<link href="https://use.fontawesome.com/releases/v5.0.10/css/all.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class="menu-btn btn fg-create"><i class="fa fa-plus fa-fw"></i><i class="arrow fa fa-fw"></i>Menu</div>
<div class="menu">
<div class="btn-opt btn fg-shopping-bag" id="shopping-bag">
<label for="shopbtn"><input id="shopbtn" name="toggler" type="radio"><i class="fa fa-fw fa-shopping-bag"></i> Bag</label>
</div>
<div class="btn-opt btn fg-rocket" id="rocket">
<label for="rocketbtn"><input id="rocketbtn" name="toggler" type="radio"><i class="fa fa-fw fa-rocket"></i> Rocket</label>
</div>
</div>
</div>

Categories