javascript – OnClick event assignment using document.getElementById

Question:

Code

function asignarEventos() {

  var uno = document.getElementById("uno");
  var dos = document.getElementById("dos");
  var tres = document.getElementById("tres");

  var arreglo = [uno, dos, tres];

  for (var i = 0; i < arreglo.length; i++) {

    var elemento = arreglo[i];
    var texto = elemento.innerHTML.trim();

    elemento.onclick = function(){
      alert(texto);
    };

  }

}

asignarEventos();
<html>

<head>
</head>

<body>

  <a id="uno">
    Uno
  </a>

  <a id="dos">
    Dos
  </a>

  <a id="tres">
    Tres
  </a>

</body>

</html>

Target

The arreglo variable contains a list of HTML elements, previously obtained using document.getElementById() . Later I want to .onclick assign an event to the HTML element using the .onclick property of the DOM Element.

What I want is that when clicking on any of the <a> elements, an alert() is displayed or a function is executed showing the text contained in them.


Trouble

In this section of the code:

var elemento = arreglo[i];
var texto = elemento.innerHTML.trim();

elemento.onclick = function(){
  alert(texto);
};

I obtain the element contained in the variable arreglo , and later I innerHTML its innerHTML value, that is, the text that it contains, then I assign the onclick attribute assigning an anonymous function that will execute an alert() showing the text that the HTML element contains.

But when clicking on any of the elements, the innerHTML of the last element is always printed, in this case it is the word "three". When should be the value of each element individually.


Ask

How can an onClick() event be assigned to an element obtained with document.getElementById() ?


Note

It should be clarified that I must solve the problem using pure JavaScript , it is useless for me to use a library such as jQuery or others, since in that environment I cannot make use of it.

Answer:

The problem occurs because of scope issues. Remember:

A variable declared with var always has a function scope or a global scope. Any variable declared within a function, whether or not it is within a block or structure, always applies to hoisting .

Example hosting

// ES5
(function() {
  for (var i = 0; i < 3; i++) {
    var x = i;
  }
  console.log(x);
})();

// ES6
(() => {
  for (let i = 0; i < 3; i++) {
    let y = i;
  }
  console.log(y); // error
})();

As you can see, in the first example, x is still available even outside the for loop, this happens because ES5 variables undergo a different process when they are declared; this does not happen in ES6 with let and const .

In your code, the texto variable, being function-scoped, always saves the last reference assigned to it , that is, the text of the last element of the array. What you should do is use a closure or use let or const .

function asignarEventos() {
  var arreglo = Array.from(document.querySelectorAll('a[id]'));

  for (var i = 0; i < arreglo.length; i++) {
    var elemento = arreglo[i];
    const texto = elemento.innerHTML.trim();
    elemento.onclick = function() {
      alert(texto);
    };
  }
}

asignarEventos();
<body>
  <a id="uno">
    Uno
  </a>
  <a id="dos">
    Dos
  </a>
  <a id="tres">
    Tres
  </a>
</body>
Scroll to Top