Reputation: 11
I have got 16 divs of the same class name in html document in the following fashion
<div class="game-selection-tab">
<h2>30m + 15s</h2>
</div>
<div class="game-selection-tab">
<h2>60m + 0s</h2>
</div>
<div class="game-selection-tab">
<h2>Custom</h2>
</div>
I want to create onclick method that returns h2 text content from particular div. I tried to solve this by using following javascript code.
var selectionTabs = document.getElementsByClassName("game-selection-tab");
for(var i = 0; i < selectionTabs.length; i++){
var tab = selectionTabs[i];
var content = tab.getElementsByTagName("h2");
tab.onclick = function(){
console.log(content[0].textContent);
}
}
The problem is: no matter which div i click, program always returns h2 text content from the last div(in this example "custom").
Upvotes: 0
Views: 410
Reputation: 370
Assuming that you don't wanna change your HTML to include an "onclick" event on each h2, this code might help you:
document.addEventListener('click', function(e) {
e = e || window.event;
var target = e.target || e.srcElement,
text = target.textContent || text.innerText;
console.log(text);
}, false);
EDIT If you want to be more specific and get the content from only your h2's, you could use this:
h2s = document.getElementsByTagName('h2');
for (var i = 0; i < h2s.length; i++) {
h2s[i].addEventListener('click', redirect, false);
}
function redirect(e) {
var target = e.target || e.srcElement;
var text = target.textContent || text.innerText;
console.log(text);
}
Upvotes: 0
Reputation: 948
Try this simple solution:
var els = document.getElementsByClassName('game-selection-tab');
var index = 0;
function getText() {
alert(this.innerText || this.textContent);
}
for (; index < els.length; index++) {
els[index].onclick = getText;
}
<div class="game-selection-tab">
<h2>30m + 15s</h2>
</div>
<div class="game-selection-tab">
<h2>60m + 0s</h2>
</div>
<div class="game-selection-tab">
<h2>Custom</h2>
</div>
Upvotes: 0
Reputation: 336
Can you try the solution below.
var selectionTabs = document.getElementsByClassName("game-selection-tab");
Object.keys(selectionTabs).forEach((data, index) => {
var context = selectionTabs[data].getElementsByTagName("h2")[0].textContent;
selectionTabs[data].onclick = function () {
console.log(context)
}
})
Upvotes: 0
Reputation: 56744
Replace
var i = 0
by
let i = 0
and you're done.
A detailed explanation is here.
I'll quote my answer for your understanding below.
scope
Check this example to understand the problem:
var
creates function scope
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i)
})
}
funcs.forEach(function(func) {
func()
})
While you might expect this forEach
loop to result in number 0
to 9
being printed, instead you get ten times 10
. The cause of this is the variable i
being declared using var
keyword, which creates a function scope
that leads to each function
in funcs
holding a reference to the same i
variable. At the time the forEach
loop is executed, the previous for
-loop has ended and i
holds 10 (9++ from the last iteration).
Compare how ES6's let
, which creates block scope
instead of function scope
, behaves in this regard:
let
(ES6 or officially ES2015) creates block scope
:var funcs = []
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i)
})
}
funcs.forEach(function(func) {
func()
})
Because let
creates block scope
, each iteration of the for
loop has its "own" variable i
.
IIFE
wrapperIf you need an ES5 solution, an IIFE (immediately invoked function expression) wrapper would be the way to go:
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value)
}
}(i)))
}
funcs.forEach(function(func) {
func()
})
Here, i
is passed as a parameter to each function which stores its own copy value
.
for..in
loops:var funcs = [],
obj = {
first: "first",
last: "last",
always: "always"
}
for (var key in obj) {
funcs.push(function() {
console.log(key)
})
}
funcs.forEach(function(func) { // outputs: "always", "always", "always"
func()
})
Again, all functions in funcs
hold the reference
to the same key
because var key
creates a function scope that lives outside of the for..in
loop. And again, let
produces the result you'd probably rather expect:
var funcs = [],
obj = {
first: "first",
last: "last",
always: "always"
}
for (let key in obj) {
funcs.push(function() {
console.log(key)
})
}
funcs.forEach(function(func) {
func()
})
Also compare the excellent (!) book
Nicholas C. Zakas: "Understanding ES6", no starch press, p. 8-9.
from which the examples were taken.
Upvotes: 2
Reputation: 2804
It's showing always the same value because you are setting content outside of the onclick
function. After the for loop, content
points to the last h2.
Move the content definition inside the onclick
function.
tab.onclick = function(){
var content = this.getElementsByTagName("h2");
console.log(content[0].textContent);
}
Upvotes: 1
Reputation: 1570
Try this
var selectionTabs = document.getElementsByClassName("game-selection-tab");
for(var i = 0; i < selectionTabs.length; i++){
(function (index) {
var tab = selectionTabs[index];
var content = tab.getElementsByTagName("h2");
tab.onclick = function(){
console.log(content[0].textContent);
}
})(i);
}
The thing is by the time your event attaches to the actual DOM element the for loop execution is complete and the value of i is the max value that it can reach. Hence, isolating the same in a function like this works. The function stores the value of i
or in this case index
as the original value that you expect.
Upvotes: 2