Reputation: 33
I'm trying to add an event that changes the text of a button when I click on it. However it doesn't matter which one I click, it always changes the text of the last button.
At first I tried by passing the button to the method "pulsar", and always the last button was the one changing. I thought it may be the reference of the variable so I tried passing the possition, but the same happens.
class Buscaminas{
constructor () {
this.botones = [];
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 7; j++) {
let boton = document.getElementById(i + "" + j);
boton.textContent = "Hi";
boton.onclick = e => {
this.pulsar(6*i+j);
}
this.botones.push(boton);
}
}
}
pulsar = (n) => {
console.log(n);
this.botones[n].textContent = "Bye";
}
}
The console.log always prints 55
Upvotes: 0
Views: 334
Reputation:
You could try this:
function sayHello(e) {
e.target.textContent = "Darth Vader";
}
var buttons = document.querySelectorAll("button");
buttons.forEach(e => e.addEventListener("click", sayHello, false));
<button>Hello</button>
<button>I</button>
<button>Am</button>
<button>Your</button>
<button>Father</button>
Upvotes: 1
Reputation: 42317
You're approaching this incorrectly.
You never want to add a bunch of individual event handlers to each element in a case where you have lots of elements. You want to create a single event handler at a root node where click events for each child element bubble up to.
In this example, we have 10 divs:
<div id="btn-root">
<input type="button" class="btn" value="1">
<input type="button" class="btn" value="2">
<input type="button" class="btn" value="3">
<input type="button" class="btn" value="4">
<input type="button" class="btn" value="5">
<input type="button" class="btn" value="6">
<input type="button" class="btn" value="7">
<input type="button" class="btn" value="8">
<input type="button" class="btn" value="9">
<input type="button" class="btn" value="10">
</div>
And we have this simple code that listens for clicks on any of the child ".btn" elements:
class Buscaminas {
constructor() {
document.querySelector('#btn-root').addEventListener('click', (evt) => {
evt.target.textContent = Math.random();
});
}
}
new Buscaminas();
If you run that, you'll see that every time you click one of the buttons, its content is replaced with a random number.
Later edit:
Say you're in the case where you want to find the index of the element being clicked. We still don't want to assign individual event handlers for each element, but we aren't provided with the index of the target element in the parent.
To get around this, we want to search through the child nodes of #btn-root
until it matches. A binary search won't work here, but we want something better than indexOf
which just does a linear search. What we can do instead is only loop for the length of half the array and check both ends. Then we can get the index fairly efficiently.
document.querySelector('#btn-root').addEventListener('click', (ev) => {
const children = ev.target.parentNode.children;
for (let i = 0; i < Math.floor(children.length / 2); i++) {
const lowMatch = ev.target === children[i] && i;
const highMatch = ev.target === children[children.length - 1 - i] && children.length - 1 - i;
const index = Number.isInteger(lowMatch) && lowMatch || Number.isInteger(highMatch) && highMatch;
if (index) {
ev.target.value = `${index + 1}-${Math.random()}`;
break;
}
}
});
Upvotes: 1