onclick() not working on first click for HTML table - javascript

So I made a 5x5 grid using HTML's <table> element. I want each cell to turn red when it is clicked and revert back to white when it isn't. It looks like it won't detect the first ever click on each cell. Once the first click has been triggered, it alternates from red and white normally under 1 click, but when you click it for the very first time for that instance, it does not respond. Why is it that a cell responds on the first click after it has been clicked on twice, but doesn't respond on the first click if it has never been touched before?
HTML snippet:
<div class="board">
<table type="board">
<tr>
<td id="r1-c1" onclick="changeColor('r1-c1')"></td>
<td id="r1-c2" onclick="changeColor('r1-c2')"></td>
<td id="r1-c3" onclick="changeColor('r1-c3')"></td>
<td id="r1-c4" onclick="changeColor('r1-c4')"></td>
<td id="r1-c5" onclick="changeColor('r1-c5')"></td>
</tr>
...
</table>
</div>
<button id="submit" onclick="submitted()">Generate</button>
The snippet is nested inside body and 2 div tags respectively.
CSS snippet:
table[type=board],tr,td{
background-color: white;
min-width: 80px;
min-height: 380px;
border: 2px solid black;
text-align: center;
font-size: 25px;
margin: 0px;
}
JS code:
function changeColor(id)
{
if(document.getElementById(id).style.backgroundColor == "white"){
document.getElementById(id).style.backgroundColor = "red";
}else{
document.getElementById(id).style.backgroundColor = "white";
}
}

Use the following code. It will work.
function changeColor(id){
if( (document.getElementById(id).style.backgroundColor == "white") || (document.getElementById(id).style.backgroundColor == "")){
document.getElementById(id).style.backgroundColor = "red";
}else{
document.getElementById(id).style.backgroundColor = "white";
}
}

You have not provided the HTML, So I have to create the DOM.
document.getElementById(id).style.backgroundColor
Do you mean to say each of the cell has an id?
Which may be too complex for large grid. Instead you should use rowIndex & cellIndex to locate a particular cell.
Also you can use event object and find the target. Saying that it mean event.target will help you to locate the cell which is clicked
var getTable = document.getElementById("demoTable");
//Declare a variable to hold the cellIndex & rowIndex
// On next click check if this values,& if not null change the background color of that cell
var col = "";
var row = "";
getTable.addEventListener('click',function(event){
console.log(col,row)
if(col !== "" && row !== "" ){
document.getElementById('demoTable').rows[row].cells[col].style.backgroundColor ="transparent" ;
}
col = event.target.cellIndex;
row = event.target.parentNode.rowIndex;
//Set background of the cell on which it is clicked
document.getElementById('demoTable').rows[row].cells[col].style.backgroundColor ="red" ;
})
JSFIDDLE

Related

Set <div> background color on load, then change between 3 colors when clicked

I am trying to set the background color of a div upon page load to blue. Then I want to cycle through 3 different colors (red, yellow, and green) when clicked and have the selected color remain. Below is my sample code. You can see the first two do nothing when clicked due to setting the blue color on load. I didn't load the 3rd div to blue on load to show how I want the behavior to act once clicked. Any help is appreciated.
function colorload() {
var element = document.getElementById("day1");
element.style.backgroundColor = "blue";
var element = document.getElementById("day2");
element.style.backgroundColor = "blue";
}
function changeColor(e, numb) {
var color = e.className;
e.className = (color == 'red') ? 'amber' :
(color == 'amber') ? 'green' :
(color == 'green') ? 'red' :
'undefined';
}
<style onload="colorload()">
.red {background-color:red;}
.amber {background-color:yellow;}
.green {background-color:green;}
div {
width:200px;
height:100px;
margin:50px;
text-align: center;
vertical-align: middle;
line-height: 90px;
font-weight:bold;
user-select: none;
cursor:pointer;
}
</style>
<html>
<body>
<div class="red" id="day1" onclick="changeColor(this, 1)">One</div>
<div class="green" id="day2" onclick="changeColor(this, 2)">Two</div>
<div class="amber" id="day3" onclick="changeColor(this, 3)">Three</div>
</body>
</html>
i made an update to your html and JS codes,
i used in this example .style instead of css classes, if you are interested on using classes you can refer to my comments and this link on mdn it's pretty simple.
Html file
<html>
<body>
<!-- i used .btn class and data-col to play with indexes -->
<div class="btn" id="day1" data-col="0" onclick="changeColor(event)">One</div>
<div class="btn" id="day2" data-col="0" onclick="changeColor(event)">Two</div>
<div class="btn" id="day3" data-col="0" onclick="changeColor(event)">Three</div>
</body>
</html>
Js file
let divs;
let colors = ['blue', 'red', 'green' , 'yellow'];
// when loading the page, we are catching all divs having the class "btn"
// to render it with Blue background
document.body.onload = function() {
divs = document.querySelectorAll('.btn');
divs.forEach(btn => {
const selectedColorIndex = btn.dataset.col;
btn.style = 'background:'+colors[selectedColorIndex];
});
};
function changeColor(e) {
// catch the clicked div which passed by the "event" value in the html file
let divElement = e.target;
// get data-col value and convert it to number with (+)
const selectedColorIndex = +divElement.dataset.col;
// check if we have a next color or get the red index
const nextSelectedColor = selectedColorIndex +1 >= colors.length?1:selectedColorIndex+1;
// update data-col with the next new color index to conserve the iteration (loop)
divElement.dataset.col = nextSelectedColor;
// if you want to use classes you can access with
// .classList.add(..) and .classList.remove(..) OR
// .classList.toggle(..)
divElement.style = 'background:'+ colors[nextSelectedColor]; // update the element background with selected color
}
You can also replay the same codes or update: it here is the full replayed code in JSFiddle which i made to make it more easy.

using event delegation to highlight cell in the table

I don't understand this js code here in this example. This code is to highlight a cell on click. Instead of assigning an onclick handler to each (can be many) – we’ll setup the “catch-all” handler on element. It will use event.target to get the clicked element and highlight it. But I don't understant the js part here. I want detailed explanation for it and if there any other method to do the same thing.
let table = document.getElementById('bagua-table');
let selectedTd;
table.onclick = function(event) {
let target = event.target;
while (target != this) {
if (target.tagName == 'TD') {
highlight(target);
return;
}
target = target.parentNode;
}
}
function highlight(node) {
if (selectedTd) {
selectedTd.classList.remove('highlight');
}
selectedTd = node;
selectedTd.classList.add('highlight');
}
#bagua-table td {
width: 150px;
text-align: center;
padding-top: 5px;
padding-bottom: 12px;
background-color:#000;
color: #fff;
}
#bagua-table .highlight {
background: red;
}
<table id="bagua-table">
<tr>
<td class="nw"><strong>Northwest</strong></td>
<td class="n"><strong>North</strong></td>
<td class="ne"><strong>Northeast</strong></td>
</tr>
<tr>
<td class="w"><strong>West</strong></td>
<td class="c"><strong>Center</strong></td>
<td class="e"><strong>East</strong></td>
</tr>
<tr>
<td class="sw"><strong>Southwest</strong></td>
<td class="s"><strong>South</strong></td>
<td class="se"><strong>Southeast</strong></td>
</tr>
</table>
What the code is doing is handling the event at the <table>. When a user clicks any one of the cells an event is generated and bubbles up to parent elements. The initial target in this case is the cell that was clicked and the if (target.tagName == 'TD') code block is triggered. This in turn calls the highlight function to set the new highlighted cell by removing the .highlight class from last highlighted cell and add it to the currently targeted one.
In order to be more robust, the code doesn't make an assumption about what element generates the event, because the <td> cells can also contain other html tags. This is why it needs to have the while (target != this) loop. The original target might not be a <td> tag but one of it's ancestors will be.

Color table row based on column value

I have an html table and I want to color the rows based on the value in the first column of that row. If the value is "CONFIRMED" I want to color the row green, and if it is "UNCONFIRMED" I want to color the row red.
The JS I am using to do this is:
$(function(){
$("tr").each(function(){
var col_val = $(this).find("td:eq(1)").text();
if (col_val == "CONFIRMED"){
$(this).addClass('selected'); //the selected class colors the row green//
} else {
$(this).addClass('bad');
}
});
});
The CSS looks like this:
.selected {
background-color: green;
color: #FFF;
}
.bad {
background-color: red;
color: #FFF;
}
The html table is generated from a pandas dataframe in my Django view and passed in like this:
<div class="table-responsive" style="margin-left: 15%; margin-right: 15%; overflow:auto;">
{{ datatable | safe }}
</div>
The problem is that it's coloring all of my rows red. Can anyone tell me what I'm doing wrong?
Since you use ==="CONFIRMED" make sure it's really: UPPERCASE, and that there's no leading or ending spaces " CONFIRMED" or "CONFIRMED " in the HTML.
The code you're showing will color .selected the entire row whos :eq(1) TD has the "CONFIRMED" content:
$(function(){
$("tr").each(function(){
var col_val = $(this).find("td:eq(1)").text();
if (col_val == "CONFIRMED"){
$(this).addClass('selected'); //the selected class colors the row green//
} else {
$(this).addClass('bad');
}
});
});
.selected{
background-color:green;
}
.bad{
background-color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td><td>CONFIRMED</td>
</tr>
<tr>
<td>2</td><td>UNCONFIRMED</td>
</tr>
</table>
nothing bad about it.
if that's not what you see on your screen note that :eq() is index based, and elements index start at 0 so :eq(0) is probably what you want?
Another probable thing is that you don't have the exact content string set as "CONFIRMED" but probably there's some spaces before or after - so make sure to trim them using $.trim()
if( $.trim(col_val) === "CONFIRMED" )
if you additionally want to make your code even more flexible about the UPPERCASE or Capitalization you can do as:
if( $.trim(col_val.toLowerCase() ) === "confirmed" )
// Will work on "CONFIRMED", "Confirmed", "conFIRMed" etc
<style>
tr[data-stat="confirmed"]{
background-color: green;
color: #fff;
}
tr[data-stat="unconfirmed"]{
background-color: red;
color: #fff;
}
</style>
<table>
<tr data-stat="confirmed">
<td>1</td>
<td>Confirmed</td>
<td>bla.. bla.. bla..</td>
</tr>
<tr data-stat="unconfirmed">
<td>2</td>
<td>Not Confirmed</td>
<td>bla.. bla.. bla..</td>
</tr>
</table>
To find the first column in a row, you want to use the first-child selector. You can iterate over every first column with the each function.
We then look at the text and then add the appropriate class to the column's parent (tr).
$(document).ready(function() {
$("td:first-child").each(function() {
if ($(this).text() === "Confirmed") {
$(this).parent().addClass("green");
}
else {
$(this).parent().addClass("red");
}
});
});
http://jsfiddle.net/cw43ejjf/
If you are looking for the first column in the row you want to use:
var col_val = $(this).find("td:eq(0)").text();
Change the td:eq(1) to td:eq(0)

Javascript show/hide div requires two clicks

I've got code to show/hide two divs based upon the clicking of an arrow. However, the second div requires two clicks before it hides and the arrow doesn't change as expected. The top div works perfectly. Any suggestions about what I'm doing wrong, please?
EDIT - Thanks to the two posters who have pointed out my naming error in the arrows. However, after loading the page, the second div still requires two clicks before it toggles.
HTML
<div id="start_conditions_arrow" class="arrow_down" onclick="toggleDiv('start_conditions')"></div>
<h2>Starting Conditions</h2>
<div id="start_conditions">
<%= render :partial => 'start_conditions', :object => #page.start_conditions %>
</div>
<div id="probability_arrow" class="arrow_right" onclick="toggleDiv('probability_inputs')"></div>
<h2>Probability Inputs</h2>
<div id="probability_inputs">
<%= render :partial => 'probability_inputs', :object => #page.probability_inputs %>
</div>
Javascript
var toggleDiv = function(id){
var tag = document.getElementById(id).style;
if(tag.display == 'none'){
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
} else {
document.getElementById(id).style.display='none';
document.getElementById(id + '_arrow').className='arrow_right';
}
};
CSS
.arrow_down, .arrow_right {
width: 0;
height: 0;
margin: 12px 12px 0 0;
float: left;
cursor: pointer;
}
.arrow_down {
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 18px solid #d5d5d5;
}
.arrow_right {
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 18px solid #d5d5d5;
}
#probability_inputs {
display: none;
}
#start_conditions {
display: none;
}
Here's a Codepen including the above: https://codepen.io/anon/pen/yXozYJ
The second arrow element should have probability_inputs_arrow as id and not probability_arrow, as you're building its id in the function as id + '_arrow' and you pass 'probability_inputs'.
I know that I'm a little late answering this, but I have a solution. There are two issues that should be addressed and they're as follows:
The ID of the last div is incorrect as stated in PSR's answer.
The check against the style attribute of the element in the toggleDiv method doesn't account for the lacking of the style attribute upon page load.
Regarding the first issue, the ID should read probability_inputs_arrow, which fixes the issue with the arrow not being updated when it is toggled. However, the second issue needs a little more explaining...
Upon page load, the CSS provided is applied to the elements with the IDs probability_inputs and start_conditions, giving them both a display value of none. Upon clicking on either one of these arrows, you're retrieving the style attributes of the targeted element, and checking the display property which upon page load is empty. This is why it requires two clicks to achieve the desired behaviour, because the first click is effectively just setting that value in the else statement.
Here's a link to an updated Codepen that contains the fixes: https://codepen.io/anon/pen/oweELy
actually you are getting error here
The second element need to have have probability_inputs_arrow as id and not probability_arrow,
The style.display is set to "" by default when the page loads for the first time, thus it ends up in the else block and then requires a second click to go to the if block. Just add this to your else if statement.
<script>
var x = document.getElementById("myDIV");
if (x.style.display == "none")
{
x.style.display = "block";
}
else if((x.style.display == 'null')||(x.style.display == ""))
{
x.style.display = "block";
}
else
{
x.style.display = "none";
}
</script>
I had this problem and it was due to the default state of the DIV. Even if you set the DIV class value is set display: none, it appears some browser do not accept this state, and therefore it is unknown.
To solve the problem, using your own code, add another condition of default:
var toggleDiv = function(id){
var tag = document.getElementById(id).style;
if(tag.display == 'none')
{
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
}
else if(tag.display == 'block')
{
document.getElementById(id).style.display='none';
document.getElementById(id + '_arrow').className='arrow_right';
}
else
{
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
}
};
`

change select element?

I want to see if this is possible, i need to change a select element content to be displayed as divs using images just like a color picker. when the user selects clicks on a colored div i want an image to be displayed on the page. Also would i still be able to capture the selected item in a form hidden field?
It's a shirt building page, i have 12 colours, and 4 parts to a shirt. Any help, guidance would be appreciated.
My current code is below pretty basic.
function swapImage(){
var image = document.getElementById("neck");
var dropd = document.getElementById("imageneck");
image.src = dropd.value;
};
<select name="imageneck" id="imageneck" onChange="swapImage()">
<option value="WHITE-4.png">White</option>
</select>
<div id="poloneck"><img id="neck" src="WHITE-4.png" /></div>
A demo of the page image based is here ..demo
Thanks
I suggest you creating a <div> or <table> box for every picker. [Working demo]
Javascript
// instead of swapImage
function setImage(subject, color) {
var image = document.getElementById(subject);
image.src = color + ".jpg"; // e.g.: white.jpg
}
// general click event handler for changing color
function pickerClick(e) {
// event -> which box -> which color
e = e || event;
var target = e.target || e.srcElement;
if ( target.nodeName.toUpperCase() != "TD" ) return;
var color = target.className;
var picker = target.parentNode.parentNode;
// change <input> field
document.getElementById("imageneck").value = color;
// change appearance
setImage(picker, color);
}
// a specific click handler for neck
var collarbox = document.getElementById('collar');
collarbox.onclick = pickerClick;
HTML
<table class="picker" id="collar">
<tr>
<td class="white"></td>
<td class="black"></td>
<td class="red"></td>
<td class="blue"></td>
</tr>
</table>
CSS
.white { background: white }
.black { background: black; }
.red { background: red; }
.blue { background: blue; }
.picker { border: 1px solid #ccc; }
.picker td { width:30px; height: 30px; cursor: pointer; }
​
http://api.jquery.com/val/
Check the demo for select box.
You can change your color or image based on select box selected value.
You can use jquery add function for adding css or
addClass function and removeClass for changing class

Categories