I'm feeling awfully silly here - I can't get a simple class switching statement to work in jQuery! I can only sit in frustration as for the last 45 minutes, I've searched Stack Overflow questions and answers, to no avail.
My goal is, upon clicking an item with the colorClick id (already containing a default class of "white"), to rotate that item between being assigned the class green, yellow, orange, red, and back to white again (ad infinitum).
The CSS is simple - each class simply corresponds to a different background color.
The HTML is simple - a div tag with two CSS classes (one static, one to be changed by jQuery).
The jQuery is simple - read the class on the clicked item, and change it.
And now, you understand what vexes me. Here's what I'm working with so far:
$("#colorClick").click(function () {
if ($(this).hasClass('white')) {
$(this).removeClass("white").addClass("green");
} else if ($(this).hasClass('green')) {
$(this).removeClass('green').addClass('yellow');
} else if ($(this).hasClass('yellow')) {
$(this).removeClass('yellow').addClass('orange');
} else if ($(this).hasClass('orange')) {
$(this).removeClass('orange').addClass('red');
} else if ($(this).hasClass('red')) {
$(this).removeClass('red').addClass('white');
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
I'm feeling awfully silly here - I can't get a simple class switching statement to work in jQuery! I can only sit in frustration as for the last 45 minutes, I've searched Stack Overflow questions and answers, to no avail.
My goal is, upon clicking an item with the colorClick id (already containing a default class of "white"), to rotate that item between being assigned the class green, yellow, orange, red, and back to white again (ad infinitum).
The CSS is simple - each class simply corresponds to a different background color.
The HTML is simple - a div tag with two CSS classes (one static, one to be changed by jQuery).
The jQuery is simple - read the class on the clicked item, and change it.
And now, you understand what vexes me. Here's what I'm working with so far:
$("#colorClick").click(function () {
if ($(this).hasClass('white')) {
$(this).removeClass("white").addClass("green");
} else if ($(this).hasClass('green')) {
$(this).removeClass('green').addClass('yellow');
} else if ($(this).hasClass('yellow')) {
$(this).removeClass('yellow').addClass('orange');
} else if ($(this).hasClass('orange')) {
$(this).removeClass('orange').addClass('red');
} else if ($(this).hasClass('red')) {
$(this).removeClass('red').addClass('white');
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
<div class="toDoItem white" id="colorClick">To-do list item</div>
Link to the fiddle: http://jsfiddle.net/andrewcbailey89/4Lbm99v0/2/
Share Improve this question edited Jan 28, 2016 at 22:32 user4639281 asked Oct 14, 2015 at 18:09 AndrewCBailey89AndrewCBailey89 932 silver badges6 bronze badges 5 |3 Answers
Reset to default 30 +400First things first, when making a list, you should use the correct list elements. Your "To Do" list fits the definition of a description list (<dl>
) so you should use that instead of <div>
elements.
You can save a lot of lines of code by getting rid of the classes and creating an array of colors. Make sure that the colors are in the same order that you want them to be shown. We will use this array to set the background color based on an incremented counter.
var colors = ['#b2d8b2', '#ffffb2', '#ffe4b2', '#ffb2b2', '#fff'];
You can also greatly simplify your script by using a "factory" function which defines a scope and builds an event listener function, which it returns. This creates a "safe" scope for each listener function to reside in that we can define variables which will store information between events.
In the following snippet, we define a count
variable that we increment on each click. We use the incremented variables remainder when dividing by the length of the color array using the modulo operator %
. If the number is smaller than the length of the array, it will return the number, otherwise it will return the remainder when dividing by the length of the array, allowing us to loop through continuously.
function todoItemListener() {
var count = 0;
return function () {
$(this).css({ 'background-color': colors[count++ % colors.length] });
}
}
Then instead of assigning the function declaration as normal (without the parenthesis), we assign the result of the factory function, simply append the parenthesis and the function will execute and return the resulting listener function. This allows us to add as many listener functions as we want, so if you're adding new todo list items, we can simply build another listener function.
$('.todo-list dd').each(function () {
$(this).on('click', todoItemListener());
});
$('.add-item').on('click', function () {
var list = this.parentNode.parentNode;
$('<dd>To-do list item</dd>').appendTo(list).on('click', todoItemListener());
});
This method also allows you to easily change the array of colors at will. So say if an option is selected somewhere on the page, another color could become available, or not available.
Also, for some extra UX goodness, I added CSS to stop selection of the text on click (that can get annoying) and to change the cursor to a pointer to give it a more actionable feel.
Here is the full demo, I've included multiple to-do lists to show that it can be done.
var colors = ['#b2d8b2', '#ffffb2', '#ffe4b2', '#ffb2b2', '#fff'];
function todoItemListener() {
var count = 0;
return function () {
$(this).css({ 'background-color': colors[count++ % colors.length] });
}
}
$('.todo-list dd').each(function () {
$(this).on('click', todoItemListener());
});
$('.add-item').on('click', function () {
var list = this.parentNode.parentNode;
$('<dd>To-do list item</dd>').appendTo(list).on('click', todoItemListener());
});
.glyphicon-plus-sign {
font-size: 15px;
}
.todo-list {
background: #efefef;
padding: 3px;
}
.todo-list dd {
margin: 0;
text-align: left;
padding: 3px;
margin-bottom: 7px;
border: 1px solid;
border-color: #e8e7e7;
background-color: #fff;
}
.add-item, .todo-list dd {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
cursor: pointer;
}
.add-item {
float: right;
margin: 4px;
}
.todo-list dh::after {
content: "";
display: block;
clear: both;
}
.todo-list dh h3 {
float: left;
margin: 0px;
max-width: 100%;
overflow: hidden;
}
/* This rule is for the demo only */
.wrp {
float: left;
width: 33.33333333%;
padding: 1px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="wrp">
<dl class="todo-list" id="todo-list-1">
<dh>
<h3 class="center" contenteditable>To Do List 1</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
<div class="wrp">
<dl class="todo-list" id="todo-list-2">
<dh>
<h3 class="center">To Do List 2</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
<div class="wrp">
<dl class="todo-list" id="todo-list-3">
<dh>
<h3 class="center">To Do List 3</h3>
<span class="add-item glyphicon glyphicon-plus-sign"></span>
</dh>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
<dd>To-do list item</dd>
</dl>
</div>
You are missing some quotes in a few places, and you didn't close the last if statement.
ex: $(this).hasClass(green)
should be $(this).hasClass('green')
Additionally, you should change colorClick
to a class rather than an ID, as there are multiple of these elements.
I also changed all of your quotes to single quotes for consistency's sake.
Here is a working snippet:
$(".colorClick").click(function () {
if ($(this).hasClass('white')) {
$(this).removeClass('white').addClass('green');
} else if ($(this).hasClass('green')) {
$(this).removeClass('green').addClass('yellow');
} else if ($(this).hasClass('yellow')) {
$(this).removeClass('yellow').addClass('orange');
} else if ($(this).hasClass('orange')) {
$(this).removeClass('orange').addClass('red');
} else if ($(this).hasClass('red')) {
$(this).removeClass('red').addClass('white');
}
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="colorClick toDoItem white">To-do list item</div>
<div class="colorClick toDoItem white">To-do list item</div>
<div class="colorClick toDoItem white">To-do list item</div>
First you are using same id
for multiple elements. id
should be unique for each element. You can use toDoItem
class
instead of colorClick
id
to bind click event. To get rid of complex if else
statement you can put all class
in an array in your required sequence. Then on click of toDoItem
change class
according to the sequence of array. If you reached at the last item of array then go back to first.
var colors = ['white', 'green', 'yellow', 'orange', 'red'];
var total = colors.length-1;
$(".toDoItem").click(function() {
var color = $(this).attr('class').split(' ')[1];
var index = colors.indexOf(color);
index = index==total? 0 : index+1;
$(this).removeClass(color).addClass(colors[index]);
});
.toDoItem {
text-align: left;
padding: 3px;
margin-bottom: 5px;
border: 1px solid;
border-color: #e8e7e7;
}
.white {
background-color: #ffffff;
}
.green {
background-color: #b2d8b2;
}
.yellow {
background-color: #ffffb2;
}
.orange {
background-color: #ffe4b2;
}
.red {
background-color: #ffb2b2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="toDoItem white">To-do list item</div>
<div class="toDoItem white">To-do list item</div>
<div class="toDoItem white">To-do list item</div>
start voting to delete with a vengeance!
What?! – A. Wolff Commented Jan 27, 2016 at 10:20