event handler not working properly in loop - javascript

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.

Related

How to combine getElementByTagName and getElementByClass using javascript

I am trying to make my selector so when it gets the class of transform with the tagname with p, it will do some event in my case it is mouse hovering but i am having trouble with it.
I know there are jquery solutions but i am doing it with pure javascript. here is the code below currently
var hoverEvent = document.getElementsByTagName("p").getElementsByClassName("transform");
for (let i = 0; i < hoverEvent .length; i++) {
hoverEvent [i].onmouseover=function() {
this.style.color = "yellow";
// changes paragraph with class of transform to yellow during hover
}
} // end for
for (let i = 0; i < hoverEvent .length; i++) {
hoverEvent [i].onmouseout=function() {
this.style.color = "black";
// changes it back to black
}
}
You can use a CSS selector in querySelectorAll to find all paragraphs with that classname:
var hoverEvent = document.querySelectorAll("p.transform");
var transformPs = document.querySelectorAll("p.transform");
for (let i = 0; i < transformPs .length; i++) {
// on mouse over
transformPs[i].onmouseover = function () {
this.style.color = "yellow";
// changes paragraph with class of transform to yellow during hover
};
// on mouse out
transformPs[i].onmouseout = function () {
this.style.color = "black";
// changes it back to black
};
}
you can use classList to check class of element
var p = document.getElementsByTagName("p");
if (p.classList.contains('transform')){
// do whatever you want to do
}
The vanilla JavaScript equivalent would be using document.querySelectorAll:
function turnYellow (e) { e.target.style.color = 'yellow' }
function turnBlack (e) { e.target.style.color = '' }
document.querySelectorAll('p.transform').forEach(function (p) {
p.addEventListener('mouseover', turnYellow)
p.addEventListener('mouseout', turnBlack)
})
body { background: #ccc; }
<p class="transform">Example Paragraph</p>
However, I think the best approach would be to forego the JavaScript altogether and instead rely on the CSS pseudo-selector :hover:
body { background: #ccc; }
p.transform:hover {
color: yellow;
}
<p class="transform">Example Paragraph</p>

How can i remove an event listener from multiple elements in JavaScript?

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];

Search function for the same class name

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;

javascript change color after each event

I have three elements, the first element clicked needs to change, lets say to red. no matter what element is clicked. The second element clicked needs to turn green then last element clicked needs to turn blue. When these elements are clicked a second time they need to turn back to white.
The first element is not a problem but how do I move on to change the other elements?
css
.container {
background-color: #ffffff;
border: 1px solid blue;
border-radius: 10px;
width: 100px;
height: 50px;
}
.red { background-color: #ff0000; }
.green { background-color: #00ff00; }
.blue { background-color: #0000ff; }
html
<div class='container' id='1' onclick='changeColor(1);'></div>
<div class='container' id='2' onclick='changeColor(2);'></div>
<div class='container' id='3' onclick='changeColor(3);'></div>
javascript
function changeColor(whichOne)
{
var element = document.getElementById(whichOne);
if ( whichOne == 1 || whichOne == 2 || whichOne == 3 )
{
element.classList.toggle("red");
}
}//end
The general process for something like this is:
Use an Array to hold the values you want to cycle through and a counter to indicate the position of the next value to use.
When you need to apply a value, pull it from the Array using the counter as the index.
After using a value, increment the counter so it indicates the next value in the Array. If the counter has reached the end of the Array, reset it back to 0.
Here is an example:
var valuesToUse = ['classA', 'classB', 'classC'],
nextIndex = 0;
function applyValue(target) {
var value = valuesToUse[nextIndex];
nextIndex = (nextIndex + 1) % valuesToUse.length;
// use `value` on `target`
}
Here is this idea applied to your problem via either cycling through classnames or through color values in JavaScript.
http://jsfiddle.net/teTTR/1/
var colors = ['#ff0000', '#00ff00', '#0000ff'],
nextColor = 0;
var classes = ['red', 'green', 'blue'],
nextClass = 0;
var elms = document.querySelectorAll('.color-changer'),
len = elms.length,
i = 0;
for (; i < len; i++) {
elms[i].addEventListener('click', changeColor);
}
elms = document.querySelectorAll('.class-changer');
len = elms.length;
i = 0;
for (; i < len; i++) {
elms[i].addEventListener('click', changeClass);
}
function changeClass(event) {
var elm = event.currentTarget,
currentClass = hasClass(elm, classes);
if (currentClass) {
elm.classList.remove(currentClass);
} else {
elm.classList.add(classes[nextClass]);
nextClass = (nextClass + 1) % classes.length;
}
}
function changeColor(event) {
var element = event.currentTarget;
if (element.style.backgroundColor) {
element.style.backgroundColor = '';
} else {
element.style.backgroundColor = colors[nextColor];
nextColor = (nextColor + 1) % colors.length;
}
}
function hasClass(elm, classes) {
var len,
i;
if (isArray(classes)) {
len = classes.length;
i = 0;
for (; i < len; i++) {
if (elm.classList.contains(classes[i])) {
return classes[i];
}
}
return false;
}
return elm.classList.contains(classes) ? classes : false;
}
function isArray(item) {
return Object.prototype.toString.call(item) === '[object Array]';
}

How to add multiple divs with appendChild?

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++)

Categories

Resources