Skip to content Skip to sidebar Skip to footer

Javascript. Onclick Returns Always The Same Object

I have got 16 divs of the same class name in html document in the following fashion

30m + 15s

Solution 1:

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.


Solution 2:

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.

Cause of the problem: lack of understanding 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.

ES5 solution using an IIFE wrapper

If 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.

The same is true for 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.


Solution 3:

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);
  }

Working fiddle


Solution 4:

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

Solution 5:

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>

Post a Comment for "Javascript. Onclick Returns Always The Same Object"