OnClick event assignment using document.getElementById

8

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>

Goal

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

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

Problem

In this section of the code:

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

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

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

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

Question

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

Note

  

It should be noted that the problem I must solve using pure JavaScript , it does not help to use a library like jQuery or others, because in that environment I can not use it.

    
asked by Ivan Botero 01.08.2017 в 15:05
source

4 answers

8

The problem occurs due to scope / scope problems. Remember:

  

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

Hosting example

// 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 the ES5 variables undergo a different process when they are declared; this does not happen in ES6 with let and const .

In your code, the variable texto , being function scope, 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>
    
answered by 01.08.2017 / 15:24
source
6

For every iteration made by the for the value of the variable texto is written. Try accessing the element itself with this and thus read the content:

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];
    
    elemento.onclick = function(){
      alert(this.innerHTML.trim());
    };

  }

}

asignarEventos();
<html>

<head>
</head>

<body>

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

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

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

</body>

</html>
    
answered by 01.08.2017 в 15:24
4

Using a Closure :

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

  elemento.onclick = function(elem){
	return function(){
	   alert(elem.innerHTML.trim());
	}
  }(elemento);

  }

}

asignarEventos();
<html>

<body load="">

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

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

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

</body>

</html>

Why does not the original code work?

The function you have defined for the event onClick reads the value of the external variable texto at run time, instead of copying its value when the function is defined. Any further modification of the external variable affects the execution of the function.

    
answered by 01.08.2017 в 15:58
3

Try showing the text with a this like this:

...

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

    var elemento = arreglo[i];

    elemento.onclick = function(){
      alert(this.innerHTML.trim());
    };

  }
    
answered by 01.08.2017 в 16:18