I have designed a tabular calendar with bunch of TD / TR elements under table body.
I want a interaction on each day of table like when I click on one td element (which is one day) it will be highlighted with border and when I moved cursor and click other day this day will be highlighted and previous one will be un-highlighted . My code is like this, but the problem is the .off click function. It is not unhighlighting so all table cells become highlighted and persists. How could I fix this using jQuery?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("td.PTDC").on("click",function(){
$(this).css("background-color", "#0093e0");
$(this).css("padding", "5px");
console.log("onclick");
});
$("tbody").off("click",function(){
$(this).css("background-color", "#ffffff");
$(this).css("padding", "0px");
console.log("offclick");
});
});
</script>
============================ I observed in source that Before click it has :
<td class="PTDC PTLC OOCT" id="db_saw_1883_7_1_6" style="border-style:none;border-right:solid 1px #DADADB;border-bottom:solid 1px #DADADB;">
And after click it has :
<td class="PTDC OOCT" id="db_saw_1883_7_1_5" style="border-style: none solid solid none; border-right-width: 1px; border-right-color: rgb(218, 218, 219); border-bottom-width: 1px; border-bottom-color: rgb(218, 218, 219); background-color: rgb(0, 147, 224); padding: 5px;">
But since all my 30 days in calendar is like one day each td elements it is difficult to de-associate the format when other td elements clicked.
OP is using a primitive application that class styles cannot override. I have deduced from various clues about Tools (OP is vague) it:
= generates...HTML tables
- it uses inline styles
- if so then that would explain why styling with classes is incredibly difficult.
- Inline styles (ex. <div style='color:blue'>
) can't be overridden by rulesets in a stylesheet or even from a <style>
block with !important being the exception. Demo 3 will demonstrate 2 ways to deal with inline style attributes.
$('td').on('click', function(e) {
var tgt = e.target;
e.stopImmediatePropagation();
$('td').each(function(idx, cell) {
cell.style.backgroundColor = '#fff';
cell.style.borderColor = '#000';
if ($(cell).hasClass('today')) {
cell.style.backgroundColor = 'rgba(0, 0, 255, 1)';
cell.style.borderColor = '#aae1ff';
}
});
tgt.style.backgroundColor = '#0093e0';
tgt.style.borderColor = '#09e';
});
e.target
is the <td>
that the user has clicked.e.stopImmediatePropagation();
prevents the event from bubbling and being heard by any other listener as well.$('td').each(function(idx, cell) {...
Every <td>
will have a function ran on it.Each cell (i.e. <td>
) will have their inline style attributes set to:
cell.style.backgroundColor = '#fff';
cell.style.borderColor = '#000';
If this particular cell has the .today
class, then:
if ($(cell).hasClass('today')) {
cell.style.backgroundColor = 'rgba(0, 0, 255, 1)';
cell.style.borderColor = '#aae1ff';
}
When the for
loop is complete, change e.target
style:
tgt.style.backgroundColor = '#0093e0';
tgt.style.borderColor = '#09e';
I misinterpreted the question: OP's desired behavior is that only one cell at a time can have the .lit
class. It's an easy modification using .addClass()
, .removeClass()
and .not()
. See Demo 2.
/* Delegate the click event on all
|| td (cell).
|| Remove the .lit class on every <td>
|| and add .lit class for the clicked <td>
*/
$('td').on('click', function() {
var that = $(this);
$('td').not(that).removeClass('lit');
that.addClass('lit');
});
"...but the problem is the
.off
click function. It is not unhighlighting so all table cells become highlighted and persists. How could I fix this using jQuery?"
The behavior OP mentions is called toggling which is the ability to go back and forth between 2 "states" (e.g. state is in off and on, or light and dark, etc). In this case it is the toggling of 2 backgrounds.
The .on()
method is a function that adds an event listener on any given individual or group of elements (e.g. a $('td')
).
The .off()
method is a function that removes an event listener off of any given individual or group of elements. .off()
does not undo whatever .on()
has done, .off()
removes .on()
. So every <td>
clicked then lost the event listener registered to it.
.css()
method for styling a group of elements.lit
is the other state and the default state is <td>
without class .lit
.toggleClass()
is the method used to do this.The primary function in the following demo addresses the issue explained by OP. As a bonus I have added the following features:
Details are commented in demo
// Make a Date Object
var d = new Date();
// Get today's day as a number
var today = d.getDate();
/* Find the cell at the index number
|| (which is eq -1) and add thr .today class
*/
$('td').eq(today - 1).addClass('today');
/* On each cell, add the day number, unless
|| the cell has class .empty
*/ // Note: the syntax of string on line 19
// is ES6 Template Literal see post for ref.
$('td').each(function(index, day) {
if ($(this).hasClass('empty')) {
return
}
$(this).append(`<b>${index+1}</b>`);
});
/* Delegate the click event on all
|| td (cell).
|| callback on each td is to
|| toggle the .lit class
*/
$('td').on('click', function() {
$(this).toggleClass('lit');
});
.month {
table-layout: fixed;
width: 90%;
min-height: 250px;
border-spacing: 1px;
border: 3px outset grey
}
caption {
font-variant: small-caps
}
.month td {
border: 2px inset black;
background: #fff;
cursor: pointer;
}
td.lit {
background-color: #0093e0;
border-color: #09e;
}
td.today {
background: rgba(0, 0, 255, 1);
border-color: #aae1ff;
}
td.today.lit {
background: tomato;
border-color: red
}
td b {
font-size: .3em;
color: #123;
vertical-align: top;
display: inline-block;
margin: -7px 0 0 -5px;
}
td.today b {
color: #fff
}
.empty {
/* Prevents any mouse events
|| i.e unclickable
*/
pointer-events: none;
cursor: default;
}
<table class='month'>
<caption>October</caption>
<thead>
<tr>
<th>SUN</th>
<th>MON</th>
<th>TUE</th>
<th>WED</th>
<th>THU</th>
<th>FRI</th>
<th>SAT</th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td class='empty' colspan='4'> </td>
</tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
// Make a Date Object
var d = new Date();
// Get today's day as a number
var today = d.getDate();
/* Find the cell at the index number
|| (which is eq -1) and add thr .today class
*/
$('td').eq(today - 1).addClass('today');
/* On each cell, add the day number, unless
|| the cell has class .empty
*/// Note: the syntax of string on line 19
// is ES6 Template Literal see post for ref.
$('td').each(function(index, day) {
if ($(this).hasClass('empty')) {
return
}
$(this).append(`<b>${index+1}</b>`);
});
/* Delegate the click event on all
|| td (cell).
|| Remove the .lit class on every <td>
|| and add .lit class for the clicked <td>
*/
$('td').on('click', function() {
var that = $(this);
$('td').not(that).removeClass('lit');
that.addClass('lit');
});
.month {
table-layout: fixed;
width: 90%;
min-height: 250px;
border-spacing: 1px;
border: 3px outset grey
}
caption {
font-variant: small-caps
}
.month td {
border: 2px inset black;
background: #fff;
cursor: pointer;
}
td.lit {
background-color: #0093e0;
border-color: #09e;
}
td.today {
background: rgba(0, 0, 255, 1);
border-color: #aae1ff;
}
td.today.lit {
background: tomato;
border-color: red
}
td b {
font-size: .3em;
color: #123;
vertical-align: top;
display: inline-block;
margin: -7px 0 0 -5px;
}
td.today b {
color: #fff
}
.empty {
/* Prevents any mouse events
|| i.e unclickable
*/
pointer-events: none;
cursor: default;
}
<table class='month'>
<caption>October</caption>
<thead>
<tr>
<th>SUN</th>
<th>MON</th>
<th>TUE</th>
<th>WED</th>
<th>THU</th>
<th>FRI</th>
<th>SAT</th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td class='empty' colspan='4'> </td>
</tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
// Make a Date Object
var d = new Date();
// Get today's day as a number
var today = d.getDate();
/* Find the cell at the index number
|| (which is eq -1) and add thr .today class
*/
$('td').eq(today - 1).addClass('today');
/* On each cell, add the day number, unless
|| the cell has class .empty
*/ // Note: the syntax of string on line 19
// is ES6 Template Literal see post for ref.
$('td').each(function(index, day) {
if ($(this).hasClass('empty')) {
return
}
$(this).append(`<b>${index+1}</b>`);
});
/* Delegate the click event on all
|| td (cell).
|| See post update for details
||
*/
$('td').on('click', function(e) {
var tgt = e.target;
e.stopImmediatePropagation();
$('td').each(function(idx, cell) {
cell.style.backgroundColor = '#fff';
cell.style.borderColor = '#000';
if ($(cell).hasClass('today')) {
cell.style.backgroundColor = 'rgba(0, 0, 255, 1)';
cell.style.borderColor = '#aae1ff';
}
});
tgt.style.backgroundColor = '#0093e0';
tgt.style.borderColor = '#09e';
});
.month {
table-layout: fixed;
width: 90%;
min-height: 250px;
border-spacing: 1px;
border: 3px outset grey
}
caption {
font-variant: small-caps
}
.month td {
border: 2px inset black;
background: #fff;
cursor: pointer;
}
td.lit {
background-color: #0093e0;
border-color: #09e;
}
td.today {
background: rgba(0, 0, 255, 1);
border-color: #aae1ff;
}
td.today.lit {
background: tomato;
border-color: red
}
td b {
font-size: .3em;
color: #123;
vertical-align: top;
display: inline-block;
margin: -7px 0 0 -5px;
background: rgba(0, 0, 0, 0);
pointer-events: none;
}
td.today b {
color: #fff
}
.empty {
/* Prevents any mouse events
|| i.e unclickable
*/
pointer-events: none;
cursor: default;
}
<table class='month'>
<caption>October</caption>
<thead>
<tr>
<th>SUN</th>
<th>MON</th>
<th>TUE</th>
<th>WED</th>
<th>THU</th>
<th>FRI</th>
<th>SAT</th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td class='empty' colspan='4'> </td>
</tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Time Date(), .getDate()
Class Manipulation .toggleClass(), .addClass(), .removeClass(), .hasClass()
Event Delegation .on(), .off()
Miscellaneous
.append(),
ES6 Template Literals
.not()