Reputation: 2735
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
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.
$(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
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
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
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
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');
});
Upvotes: 1
Reputation: 753
You want to use jQuery's .on() instead of the basic event binding: https://api.jquery.com/on/
Upvotes: 0