JQuery not removing class? - javascript

So, I am trying to create blocks that cycle through some colors. Each color is defined by a class, and I remove a certain class color, then add another class color when a block is clicked. Each segment of code looks like this:
//Function 1
$('.blue').click(function(){
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$('.green').click(function(){
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
When a block is clicked a first time, the color is changed. But when I click it again, the color does not change.
I added console.log statements to monitor in Console what was happening. As an example, when I click a box that has the blue class, it adds the green class, and the blue class is removed. But when I click the same box (that is now green) I expect the second function to run, and the box to change into a yellow color. However, what I can see through the console is that the first function is trying to run again.
I checked the HTML, and the classes do change.
My question is, why is function 1 triggered when the first box is no longer a member of the blue class? Should it not be calling function 2, since it is now a member of the green class?
The CodePen is here, I am actively working on it. I will mention here when the CodePen works.
**The CodePen now works, I used $(document).on('click', '.green') instead of $('.green).click() **
Thank you!

Since you want to change the event handlers based on changed selectors you need to use event delegation.
//Function 1
$(document).on('click', '.blue', function () {
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function () {
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
In your event registration, the selectors are evaluated only once when the page is loaded, any changes done after that to the classes will not affect the registered handlers.
Code Snippet Example
$(document).on('click', '.blue', function () {
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function () {
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
$(document).on('click', '.yellow', function () {
console.log("Yellow has been clicked");
$(this).addClass('blue');
$(this).removeClass('yellow');
});
$(document).on('click', '.red', function () {
console.log("Red has been clicked");
$(this).addClass('blue');
$(this).removeClass('red');
});
.block{
display: inline-block;
width: 200px;
height: 100px;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
.yellow{
background-color: yellow;
}
.red{
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='block green'></div>
<div class='block blue'></div>
<div class='block yellow'></div>
<div class='block red'></div>

use on instead of click, because you're changing the class of your div, so you have to use .on() to get the click event bind when it changes the class
//Function 1
$(document).on('click', '.blue', function(){
console.log("Blue has been clicked");
$(this).addClass('green');
$(this).removeClass('blue');
});
//Function 2
$(document).on('click', '.green', function(){
console.log("Green has been clicked");
$(this).addClass('yellow');
$(this).removeClass('green');
});
fiddle

What you are trying to do is this: http://jsfiddle.net/drxzLqrL/1/
$(document).ready(function(){
function foo($elm){
var color = $elm.data('color');
switch (color) {
case 'blue':
$elm.addClass('green')
.removeClass('blue')
.data('color', 'green');
break;
case 'green':
$elm.addClass('yellow')
.removeClass('green')
.data('color', 'yellow');
break;
case 'yellow':
$elm.addClass('red')
.removeClass('yellow')
.data('color', 'red');
break;
case 'red':
$elm.addClass('blue')
.removeClass('red')
.data('color', 'blue');
}
}
$('.block').on('click', function(e){
foo($(e.currentTarget));
});
});
Also use .on() instead of .click(), because you have to get the event when it changes the class and .on() provide you all the functionality of both .bind() and .live()
I hope it's help! :)

You want to use jQuery's .on() instead of the basic event binding:
https://api.jquery.com/on/

You just need to use toggleClass in this case.
FIDDLE

These clicks are binded to the elements only once, so they will not be there when you change the class. Instead, bind the click event to the 'block' class. You might also want to write this a bit more efficiently with switches or if/else.
$(document).ready(function(){
$('.block').click(function(){
if($(this).hasClass('blue'))
{
$(this).addClass('green').removeClass('blue');
}
else if($(this).hasClass('green'))
{
$(this).addClass('yellow').removeClass('green');
}
else if($(this).hasClass('yellow'))
{
$(this).addClass('red').removeClass('yellow');
}
else if($(this).hasClass('red'))
{
$(this).addClass('blue').removeClass('red');
}
$('.block').click(function(){
console.log("Block has been clicked");
});
});
});
You can view it working here:
http://codepen.io/anon/pen/pvGPyx

Lets do something different here. we'll use bind on the function - prior to executing it - to pass in an object parameter, and the scope of the function (this) being the instance handled within the anonymous function, or event delegate handler.
//Common Function
function ChangeState(state, evArg)
{
console.clear();
console.log("this: %o, state: %o, evArg: %o", this, state, evArg);
$(this).addClass(state.new);
$(this).removeClass(state.old);
}
//Function 1
$(document).on("click", ".blue", function(evArg){
ChangeState.bind(this,{"old":"blue","new":"yellow"}, evArg)();
});
$(document).on("click", ".yellow", function(evArg){
ChangeState.bind(this,{"old":"yellow","new":"red"}, evArg)();
});
$(document).on("click", ".red", function(evArg){
ChangeState.bind(this,{"old":"red","new":"green"}, evArg)();
});
$(document).on("click", ".green", function(evArg){
ChangeState.bind(this,{"old":"green","new":"blue"}, evArg)();
});
.block{
display: inline-block;
width: 200px;
height: 100px;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
.yellow{
background-color: yellow;
}
.red{
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='block green'></div>
<div class='block blue'></div>
<div class='block yellow'></div>
<div class='block red'></div>

Related

jQuery event listener fires before selector applied

I am trying to make a system that would require an admin to click a delete button twice before it fires the action. if he focusout of the button, it resets.
$(".unarmed").css("filter", "grayscale(1)").removeClass("armed").click(function(e) {
$(this).css("filter", "").removeClass("unarmed").addClass("armed");
}).mouseout(function() {
$(this).css("filter", "grayscale(1)").removeClass("armed").addClass("unarmed");
});
$("body").on("click", ".armed", function() {
alert("boom");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="plus.png">
I've seen jQuery event listener fires before selector applied? but adding e.stopPropagation() causes the second click to not fire.
when e.stopPropagation() is not in the code, it does fire the second click, but together with the first click (i think this means the problem is not with the second click selector)
here is a fiddle with e.stopPropagation():
https://jsfiddle.net/3jyr72t6/
also, if you have suggestion for making it prettier, i'm open for suggestions :D
#icecub answer as snippet:
$(document).ready(function() {
$(".unarmed").css("filter", "grayscale(1)");
$(".unarmed").click(function(e) {
if ($(this).hasClass("armed")) {
console.log("boom");
}
$(this).css("filter", "").removeClass("unarmed").addClass("armed");
}).mouseout(function() {
$(this).css("filter", "grayscale(1)").removeClass("armed").addClass("unarmed");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="https://kns.im/include/img/plus.png" style="width:50px">
You can always just use the jquery dblclick event. Jquery dblclick
$(document).on("dblclick",".btn-delete",function(){
console.log("DELETE");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn-delete">DELETE</button>
You can use a simple function to detect click outside the element .. See the next example
$("img.unwait").on("click" , function(e){
let $this = $(this);
if($this.hasClass("unarmed")){
$this.removeClass("unarmed").addClass("armed");
}else if($this.hasClass("armed")){
alert("BOOM");
$this.removeClass("armed").addClass("unarmed");
}
});
detect_click_out(".armed" , function(){
$(".armed").removeClass("armed").addClass("unarmed");
});
function detect_click_out(element_selector , action){
$(document).on('click',function(e){
if (!$(element_selector).is(e.target) // if the target of the click isn't the container...
&& $(element_selector).has(e.target).length === 0) // ... nor a descendant of the container
{action();} // run the action as a function
});
}
img{
width : 50px;
}
.unarmed{
filter : grayscale(1);
}
.armed{
filter : grayscale(0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="unwait unarmed" src="https://png.pngtree.com/element_our/sm/20180515/sm_5afb099d307d3.jpg">

How can i add a event function after append a elements?

I click the button, it will append a div inside body, then, I want to click the div to alert a msg.I tried, but fail. How can I implements with highlight area.
example
$(document).ready(function()
{
$("button").click(function()
{
div = "<div class='test'>div</div>";
$("body").append(div);
});
$(".test").click(function()
{
alert("test");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Append div</button>
You should note that when document is ready elements with the .test class do not exist (that is why your code didn't work), they are dinamically added. So, I will do like this:
$(document).ready(function()
{
$("button").click(function()
{
var div = $("<div></div>").addClass('test'); // this is creating div element in dom as jquery
// Then attach click function to purpose of its create
div.click(function()
{
alert('test')
});
$("body").append(div);// then this is appending created div
});
});
jsfiddle Playground
One way, is just registering the listener on click event after you append it to the body tag, taking care of unregistering the previous clicks events, so you don't fall on multiple clicks events on the same element. Note that when document is ready still don't exists any element with the class .test, thats the reason your code was not working. Check next example:
$(document).ready(function()
{
$("button").click(function()
{
var div = "<div class='test'></div>";
$("body").append(div);
$(".test").unbind("click").click(function()
{
alert("A new div was clicked!");
});
});
});
.test {
width: 200px;
height: 200px;
background: red;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<button type="button">Append new div</button>
</body>
For dynamically created elements, use .on, lear more about .on here http://api.jquery.com/on/
$(document).ready(function(){
$("button").click(function(){
div = "<div class='test'></div>";
$("body").append(div);
});
$(document).on('click', '.test', function(){
alert("test");
});
});

Shorthand to get jquery object from event?

Is there a way to get a jquery object back from an event to reduce the amount of $(e.target) that has to be done?
For example:
$(document).on('click',"div", function(e){
$(e.target).css('color', 'red');
}
});
could be written as
$(document).on('click',"div", function(e){
e.JQUERY_target.css('color', 'red');
}
});
Is there a way to get a jquery object from the event without having to convert it?
Is there a way to get a jquery object back from an event to reduce the
amount of $(e.target) that has to be done?
Yes. Do not use jQuery for the task. jQuery is not necessary at all for the specific requirement
$(document).on("click", "div", function(e){
e.target.style.color = "red";
});
No, events give you only DOM objects. If you want to use jQuery, $() them.
You can harness the awesome power of this!
$(document).on('click', 'div', function(){
$(this).css('color', 'red');
});
Where $(this) is the current object you are running code on. In this case, you're saying that whenever a div that is a child of document is clicked on, you want to run the given code on it. Thus, this is the div that was clicked on.
You can use $(this) if you want to use jQuery methods. Or e.target if you want to use vanilla JS methods.
Using $(this) with jQuery methods:
$(document).on('click', "div", function(e) {
$(this).css('color', 'red');
});
div {
width: 100px;
height: 100px;
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Click Me</div>
Using e.target with vanilla JS methods:
$(document).on('click', "div", function(e) {
e.target.style.color = 'red';
});
div {
width: 100px;
height: 100px;
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Click Me</div>

Bind one click in jQuery mouseenter

When I click it is bind more than 5 click action.
This jQuery block are in mouseenter jquery function.
It bind more than on click.
Below is whole function.
$('.parent').mouseover(function () {
$('#elem').show();
$('#elem').on('click', function (event) {
alert('edit');
});
$(this).mouseleave(function () {
$('#elem').hide();
});
});
Your problem is that every time you put your mouse over the .parent element - you attach a new click event listener to the #elem element. If you hover that element several times (and you don't click), the click event is already attached and therefor you will get several "alerts".
Another thing to note is that with mouseover - every time you "switch" between elements that are one-inside-another (like your example) - that event is fire.
$('.parent').mouseover(function () {
console.log('mouseover fired for .parent');
$('#elem').show();
$('#elem').on('click', function (event) {
console.log('#elem clicked');
});
$(this).mouseleave(function () {
$('#elem').hide();
});
});
$('.parent1').click('#elem1', function(event) {
console.log('#elem1 clicked');
});
$('.parent1').mouseover(function () {
$('#elem1').show();
});
$('.parent1').mouseleave(function () {
$('#elem1').hide();
});
.parent, .parent1 { border: 1px solid red; width: 50px; height: 50px; margin: 25px; padding: 25px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div id="elem">
123
</div>
</div>
<div class="parent1">
<div id="elem1">
123
</div>
</div>
I had make solution from
Dekel answer
I changed this code:
$('.parent').mouseenter(function () {
$('#elem').show();
$('#elem').on('click', function (event) {
alert('edit');
setTimeout(function () {
$('#elem').unbind( "click" );
}, 100);
});
$(this).mouseleave(function () {
$('#elem').hide();
});
});
To this one: Where I bind one click per mouseenter and still can show or hide buttons
$('.parent').one('mouseenter', function () {
$('#elem').click(function (event) {
alert('edit');
});
});
$('.parent').mouseenter(function () {
$('#elem').show();
$(this).mouseleave(function () {
$('#elem').hide();
});
});

Strange behaviour with jquery .click() event

I think I'm trying to doing a simple thing but probably i miss something.
I've this little HTML
<div class="open"> OPEN</div>
with this simple CSS:
.open {
color: green;
}
.close {
color: red;
}
Now want to catch .click() events on the div but i want to select the with the class selector.
And for second i need to change the class and catch again a different .click() event based on the class. So I used this JQuery code:
$('.open').click(function() {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
});
$('.close').click(function() {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
});
But this not work:
First click: right alert, class change, text change
Second click: wrong alert, class not change, text not change
You can check this jsfiddle: JsFiddle Example
Can you help me?
Thanks
You can simply do this with:
$('.open').click(function(){
var txt = $.trim(this.textContent) == "OPEN" ? "CLOSE" : "OPEN";
$(this).toggleClass('open').text(txt);
// $(this).toggleClass('open close').text(txt);
// use the commented line if you want to toggle the classes on each click.
});
.open {
color: green;
}
.close {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="open"> OPEN</div>
you need event delegation for this. since in the beginning, there is no div with the class close, the click handler is assigned to nothing.
just wrap your div
OPEN
and assign the click handler to the main div
$('.wrapper').on("click", ".open",function() {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
});
$('.wrapper').on("click", ".close",function() {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
});
instead of $(this).removeClass('close'); $(this).addClass('open'); you shout consider to use $(this).toggleClass('open close');
https://jsfiddle.net/ezxe9ca8/2/
Try this,
$('.general').click(function() {
var status = $(this).attr('data-status');
if(status == 'open') {
alert('open');
$(this).removeClass('open');
$(this).addClass('close');
$(this).text('CLOSE');
$(this).attr('data-status', 'close');
} else if(status == 'close') {
alert('close');
$(this).removeClass('close');
$(this).addClass('open');
$(this).text('OPEN');
$(this).attr('data-status', 'open');
}
});
Then apply class to div
<div class="open general" data-status='open'> OPEN</div>
The problem is that the event handler bound to HTML element. In this case with the <div> No with the class close or open. For this reason, when you click on div only tigger the handler with alert("opne").
The solution is: Use only one handler and inside it put a 'if' stament. In pseudocode:
if class open
do someting
else if class close
do someting

Categories

Resources