i have a function that i'm working with in javascript to highlight every other row of a given table that is named by the same class ...i am running into a problem, the code works great but it will only detect the first table named with that class...i need it to perform the task for every single table named with the same class.
i've tried a few things but nothing worked...any suggestions?
thanks!
heres what i'm working with
function start(){
var list=document.getElementsByClassName("highlight");
for(i=0; i<list.length; i++){
var element= list[i].getElementsByTagName("tr");
for(i=0; i<element.length; i++)
{
if (i%2 == 0) {
element[i].className = "odd"
}
else{
element[i].className = "even";
}
}
}
}
window.addEventListener("load", start, false);
You need to use a different variable in the inner for statement.
See a working sample here:
http://codepen.io/anon/pen/wsCxG
window.onload = start;
function start(){
var list=document.getElementsByClassName("highlight");
for(i=0; i<list.length; i++)
{
var element= list[i].getElementsByTagName("tr");
for(j=0; j<element.length; j++)
{
if (j%2 == 0) {
element[j].className = "odd"
}
else{
element[j].className = "even";
}
}
}
}
what about pure css3?
tr:nth-child(odd) {
background-color: green;
}
tr:nth-child(even) {
background-color: red;
}
with highlight
.highlight tr:nth-child(odd) {
background-color: green;
}
.highlight tr:nth-child(even) {
background-color: red;
}
example
http://jsfiddle.net/RppAT/
if you want js (shorthand+while--)
function OE(){
var lists=document.getElementsByClassName("highlight"),listsLength=lists.length;
while(listsLength--){
var trs=lists[listsLength].getElementsByTagName("tr"),trsLength=trs.length;
while(trsLength--){
trs[trsLength].className=(trsLength%2==0)?'odd':'even';
}
}
}
window.onload=OE;
Related
I have a 16x16 grid of small squares. I have added a permanent "hover" effect to make the very first box turn red when I put my mouse over it. However, I want to add the same effect to all of the boxes on the page. I can't figure out how to do it - I have tried to add an event listener to the whole page and used target.nodeName and target.NodeValue, but to no avail. I have included the working version where the fix box turns red on mouseover.
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBox = document.querySelector('.smallBox');
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
The immediate problem you are having is that this is only querying, and subsequently adding an event listener to, one element.
const smallBox = document.querySelector('.smallBox');
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
In the above portion of your code, querySelector only returns the first matching element. You may be looking for querySelectorAll here which returns a NodeList of matching elements.
You have two options (perhaps others if you want to restructure your code further). The naive approach is to, in fact, query for all of the cells and add event listeners to each of them.
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBoxes = document.querySelectorAll('.smallBox');
[...smallBoxes].forEach(smallBox => {
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
})
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
Another option is to use event delegation as you identified. Here is how you can leverage that. Note: this approach is a bit tricker for an aggressive event like "mouseover" as you may get false positive targets (like the outer container for example).
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
bigContainer.addEventListener('mouseover', e => {
var target = e.target
if (target !== bigContainer) {
target.classList.add('permahover')
}
})
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
You need to use a delegation event, because all the small boxes don't exist on the page when the page is loaded (You can figure out in the inspector element that only your first box has the event listener).
So you listen the whole container (because it is always on the page on load)
bigContainer.addEventListener('mouseover', () => {
// Code for checking if we hovered a small div & if yes applying the style
});
...and then do a comparaison with the event.target (which will be the small div hovered)
if (event.target.matches('.smallBox')) {
event.target.classList.add('permahover');
}
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBox = document.querySelector('.smallBox');
bigContainer.addEventListener('mouseover', () => {
if (event.target.matches('.smallBox')) {
event.target.classList.add('permahover');
}
});
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
You can use forEach method to loop through all boxes and add eventListener on each one.
If all of them have .smallBox class you can do it like this:
const smallBoxes = document.querySelectorAll('.smallBox');
smallBoxes.forEach(box => box.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
}))
I hope it helped you!
let smallBoxes = document.querySelectorAll('.smallBox');
[...smallBoxes].forEach(el => {
el.addEventListener('mouseover', e => e.target.classList.add('permahover'));
});
you should set the eventlistener to your DOM and ask if the trigger element are one of your elements which are that specific class. So you can handle every element with that class.
var n = 16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for (var i = 1; i < n; i++) {
bigContainer.innerHTML += '<div class="row">';
for (j = 0; j < n; j++) {
bigContainer.innerHTML += '<div class="smallBox">';
}
}
document.addEventListener('mouseover', function(e) {
if (e.target && e.target.className == 'smallBox') {
var target = e.target;
target.classList.add('permahover');
}
});
Working js fiddle: https://jsfiddle.net/nwukf205/
hope i could help you :)
if you got questions just ask
Have you tried the :hover selector? Not sure if you want specify any dynamic actions here, but it's easy to do basic stuff.
https://www.w3schools.com/cssref/sel_hover.asp
a:hover {
background-color: yellow;
}
I haven't tried your example myself but something similar to this has been answered here:
Hover on element and highlight all elements with the same class
I am trying to apply some classes to html elements via foor loop. The problem is that the loop variable doesn't work correctly.
'use strict'
window.onload = function(){
var elements = document.getElementsByTagName("div")
for(var i = 0; i < elements.length; i++){
elements[i].addEventListener("click", a(this, i), false)
}
function a(e, x){
if(!e.className){
e.className = "class".concat(x)
}
else {
e.classList.remove(e.className)
}
}
}
div{
background-color: red;
}
.class0{
background-color: blue;
}
.class1{
background-color: purple;
}
As #Patrick suggested do this:
window.onload = function(){
var elements = document.getElementsByTagName("div")
for(var i = 0; i < elements.length; i++){
elements[i].addEventListener("click", a.bind(window, elements[i],i), false)
}
function a(e, x){
if(!e.className){
e.className = "class".concat(x)
}
else {
e.classList.remove(e.className)
}
}
}
You were invoking the function a and assigning its result as an event handler.
With bind you create a function that will invoke a passing as arguments the element and the index.
I'm working on a card game where the user has to select a card from a set of 4. If it is an Ace then they win if not then they lose. But I'm having some trouble removing the event listener of click from the set of cards after the first card has been clicked.
for(var i = 0; i < card.length; i++)
{
card[i].addEventListener("click",display);
}
function display()
{
this.setAttribute("src","CardImages/" + deck[this.id] + ".jpg");
this.setAttribute("class","highlight");
if(firstGo == 0)
{
firstGo++;
firstCard = this;
this.removeEventListener("click",display);
console.log("card" + deck[this.id]);
}
else
{
alert("You've already selected a card");
this.removeEventListener("click",display);
}
}
You are adding click events using a loop because you have multiple cards.
for(var i = 0; i < card.length; i++) {
card[i].addEventListener("click", display);
}
but you're removing the event listeners using
this.removeEventListener("click",display);
which will only remove the listener on the card you clicked. If you want to remove the listener on other cards too, you should also remove them in a loop.
function display() {
this.setAttribute("src","CardImages/" + deck[this.id] + ".jpg");
this.setAttribute("class","highlight");
if (firstGo == 0) {
firstGo++;
firstCard = this;
// this.removeEventListener("click",display);
for (var i = 0; i < card.length; i++) {
card[i].removeEventListener("click", display);
}
console.log("card" + deck[this.id]);
} else {
alert("You've already selected a card");
// this.removeEventListener("click",display);
for (var i = 0; i < card.length; i++) {
card[i].removeEventListener("click", display);
}
}
}
Here's a working demo.
var cards = document.getElementsByClassName("card");
for (var i = 0; i < cards.length; i++) {
cards[i].addEventListener("click", display);
}
function display() {
this.classList.add("highlight");
for (var i = 0; i < cards.length; i++) {
cards[i].removeEventListener("click", display);
}
}
.card {
float: left;
padding: 50px 40px;
border: 1px solid rgba(0,0,0,.2);
margin: 5px;
background: white;
}
.card:hover {
border: 1px solid rgba(0,0,255,.4);
}
.card.highlight {
border: 1px solid rgba(0,200,0,.5);
}
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
I'm not sure what your card array looks like, but I filled in the rest on a codepen and it seems to be successfully removing the eventListener. Is your card array referencing specific DOM elements like this for example?
var a = document.getElementById('A');
var b = document.getElementById('B');
var c = document.getElementById('C');
var card = [a, b, c];
<head>
<title>Projects</title>
<style type="text/css">
.newtable
{
width:60%;
border:3px solid brown;
font-size:18px;
border-collapse: collapse;
border-spacing: 0;
border-padding: 10;
cellspacing: 0;
}
#newtable
{
width:60%;
border:3px solid brown;
font-size:18px;
border-collapse: collapse;
border-spacing: 0;
border-padding: 10;
cellspacing: 10;
}
#newtable td
{
width:200;
background-color:gray;
border:2px solid brown;
text-align:center;
border-padding: 10;
cellspacing: 10;
}
</style>
<script type="text/javascript">
function makeTable()
{
row=new Array();
cell=new Array();
row_num=20;
cell_num=4;
tab=document.createElement('table');
tab.setAttribute('id','newtable');
tbo=document.createElement('tbody');
tbo.setAttribute('id','tabody');
for(c=0;c<row_num;c++)
{
row[c]=document.createElement('tr');
for(k=0;k < cell_num;k++)
{
cell[k] = document.createElement('td');
if (k > 0)
{
cont=document.createElement("input");
cont.setAttribute('type','text');
cell[k].appendChild(cont);
row[c].appendChild(cell[k]);
}
else
{
cont=document.createTextNode("0" + (c+1));
cell[k].appendChild(cont);
row[c].appendChild(cell[k]);
}
}
tbo.appendChild(row[c]);
}
tab.appendChild(tbo);
document.getElementById('mytable').appendChild(tab);
mytable.setAttribute("align", "top-left");
}
function GetCellValues()
{
row=new Array();
cell=new Array();
row_num=20;
cell_num=4;
tab = document.getElementsByTagName('table');
tbo = tab.getElementsByTagName('tbody');
for(=0 ; c < row_num; c++)
{
row = tbo.getElementsByTagName('tr');
for(k=0; k < cell_num; k++)
{
cell = row.getElementsByTagName('td');
{
cont=cell.getElementsByTagName('input');
{
alert(cont.value);
}
}
}
}
}
</script>
</head>
</html>
You're reading correctly by accessing the .value property, the problem lies elsewhere.
Here is a cleaner version: https://gist.github.com/anonymous/7331383
The problems you had:
First don't forget to declare the variables you're using.
You were adding to arrays (row/cell) which wasn't really needed.
The table wasn't being added to the body
Need to call makeTable() on load (the other function can be called from the console, or you can add a button for that).
unnecessary braces in GetCellValues(), use a good editor and don't forget to indent the code, to prevent this
Use console.log() to print to the console when testing, instead of alert()
And maybe other stuff I'm not remembering xD
Hope it helps.
Assign class to inputs then get by class name
var elements =document.getElementsByClassName('test');
for(var i=0;i<elements.length;i++)
{
console.log(elements[i].value);
}
I am trying to make a chessboard using javascript and creating 64 divs with it.
The problem is, that it creates only the first div.
Here is the code:
div {
width: 50px;
height: 50px;
display: block;
position: relative;
float: left;
}
<script type="text/javascript">
window.onload=function()
{
var i=0;
var j=0;
var d=document.createElement("div");
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
document.body.appendChild(d);
d.className="black";
}
else
{
document.body.appendChild(d);
d.className="white";
}
}
}
}
</script>
As t-j-crowder has noted, the OP's code only creates one div. But, for googlers, there is one way to append multiple elements with a single appendChild in the DOM: by creating a documentFragment.
function createDiv(text) {
var div = document.createElement("div");
div.appendChild(document.createTextNode(text));
return div;
}
var divs = [
createDiv("foo"),
createDiv("bar"),
createDiv("baz")
];
var docFrag = document.createDocumentFragment();
for(var i = 0; i < divs.length; i++) {
docFrag.appendChild(divs[i]); // Note that this does NOT go to the DOM
}
document.body.appendChild(docFrag); // Appends all divs at once
The problem is, that it creates only the first div.
Right, because you've only created one div. If you want to create more than one, you must call createElement more than once. Move your
d=document.createElement("div");
line into the j loop.
If you call appendChild passing in an element that's already in the DOM, it's moved, not copied.
window.onload=function()
{
var i=0;
var j=0;
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="black";
}
else
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="white";
}
}
}
}
Although what T.J. Crowder writes works fine, I would recommend rewriting it to the code below, using a documentFragment, like Renato Zannon suggested. That way you will only write to the DOM once.
window.onload = function() {
var count = 5,
div,
board = document.getElementById('board'),
fragment = document.createDocumentFragment();
// rows
for (var i = 0; i < count; ++i) {
// columns
for (var j = 0; j < count; ++j) {
div = document.createElement('div');
div.className = (i % 2 != 0 && j % 2 == 0) || (i % 2 == 0 && j % 2 != 0) ? 'black' : 'white';
fragment.appendChild(div);
}
}
board.appendChild(fragment);
};
#board {
background-color: #ccc;
height: 510px;
padding: 1px;
width: 510px;
}
.black,
.white {
float: left;
height: 100px;
margin: 1px;
width: 100px;
}
.black {
background-color: #333;
}
.white {
background-color: #efefef;
}
<div id="board"></div>
function crt_dv(){
dv=document.createElement('div'),document.body.appendChild(dv)
};
crt_dv(),dv.className='white';crt_dv(),dv.className='black';
Also use: for(i=0;i<2;i++)