Sammy I.
Sammy I.

Reputation: 2735

JQuery not removing class?

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!

Upvotes: 2

Views: 5393

Answers (7)

Arun P Johny
Arun P Johny

Reputation: 388436

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>

Upvotes: 8

Brett Caswell
Brett Caswell

Reputation: 730

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>

Upvotes: 0

gon250
gon250

Reputation: 3545

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! :)

Upvotes: 1

sbatson5
sbatson5

Reputation: 648

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

Upvotes: 0

Fares M.
Fares M.

Reputation: 1538

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

Upvotes: 1

Patrick
Patrick

Reputation: 327

You just need to use toggleClass in this case.

FIDDLE

Upvotes: 0

marcus.kreusch
marcus.kreusch

Reputation: 753

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

Upvotes: 0

Related Questions