mianfg
mianfg

Reputation: 15

Create multiple onclick events inside a for loop

I have multiple buttons with the ids "especifica-i-pj", where i goes from 1 to 4 and j goes from 1 to 3. The idea is to assign an onclick event to each one of them, without having to declare 12 functions. I thought this would solve my problem:

for ( i = 1; i <= 4; i++ ) {
    for ( j = 1; j <= 3; j++ ) {
        dom_id = "especifica-"+i.toString()+"-p"+j.toString();
        document.getElementById(dom_id).onclick = function() {
            console.log("you clicked ",dom_id)
            ponder[i-1] = 0.1 + 0.05*(j-1);
            console.log("ponder:",i,ponder[i-1])
            $("#"+dom_id).addClass("active");
            for ( k = 1; k <= 3 && k != j; k++ )
                $("#especifica-"+i.toString()+"-p"+k.toString()).removeClass("active");
        }
    }
}

However each time I click any of the buttons, my console outputs that I clicked especifica-4-p3, the last one, and outputs ponder: 5 0.25, when i==5 should not be possible, as the outer for gets to i==4.

What can I do to make this work? I have been searching online but I have not found anything about this, or even declaring functions inside for loops. Thanks.

Upvotes: 0

Views: 1358

Answers (3)

goto
goto

Reputation: 4425

Here's a fix by using data-* attributes:

for (var i = 1; i <= 2; i++) {
  for (var j = 1; j <= 3; j++) {
    var buttonId = "especifica-" + i + "-p" + j;
    var button = document.getElementById(buttonId);
    
    button.setAttribute("data-i", i);
    button.setAttribute("data-j", j);

    button.addEventListener("click", function(event) {
      console.log("i", event.target.getAttribute("data-i"));
      console.log("j", event.target.getAttribute("data-j"));
      console.log("button with id of", event.target.id, "was clicked!");
    });
  }
}
<div><button id="especifica-1-p1" type="button">especifica-1-p1</button></div>
<div><button id="especifica-1-p2" type="button">especifica-1-p2</button></div>
<div><button id="especifica-1-p3" type="button">especifica-1-p3</button></div>
<div><button id="especifica-2-p1" type="button">especifica-2-p1</button></div>
<div><button id="especifica-2-p2" type="button">especifica-2-p2</button></div>
<div><button id="especifica-2-p3" type="button">especifica-2-p3</button></div>

Learn more about data-* attributes here:


Alternatively, you could take advantage of the concept of closures, like in the following example:

for (var i = 1; i <= 2; i++) {
  for (var j = 1; j <= 3; j++) {
    var buttonId = "especifica-" + i + "-p" + j;
    var button = document.getElementById(buttonId);
    
    var createEventListener = function (iValue, jValue) {
      return function (event) {
        console.log("i:", iValue, "j:", jValue);
        console.log("button with id of", event.target.id, "was clicked!");
      }
    };
    button.addEventListener("click", createEventListener(i, j));
  }
}
<div><button id="especifica-1-p1" type="button">especifica-1-p1</button></div>
<div><button id="especifica-1-p2" type="button">especifica-1-p2</button></div>
<div><button id="especifica-1-p3" type="button">especifica-1-p3</button></div>
<div><button id="especifica-2-p1" type="button">especifica-2-p1</button></div>
<div><button id="especifica-2-p2" type="button">especifica-2-p2</button></div>
<div><button id="especifica-2-p3" type="button">especifica-2-p3</button></div>

Read more about closures here:

Also, use the element.addEventListener method instead of element.onclick. Have a look at here why it's better to use addEventListener('click', ...) instead of onclick:

Upvotes: 1

Dickens A S
Dickens A S

Reputation: 4054

The best way is to capture on click for the first level parent which is the parent for all the buttons,

Only for that you create on click,

inside the event function detect event.target which will tell from which button the click is happening

function buttonClick(event) {
    alert(event.target.getAttribute("id"));
}
<div id="parent" onclick="buttonClick(event)">
   <button id="especifica-1-p1">b11</button>
   <button id="especifica-1-p2">b12</button>
   <button id="especifica-1-p3">b13</button>
   <button id="especifica-2-p1">b21</button>
   <button id="especifica-2-p2">b22</button>
   <button id="especifica-2-p3">b23</button>
</div>

If you want to maintain the data 1,1 1,2 ... etc , you can do like this

In each button you can introduce dummy data attributes with your own name assumption

Example

<button id="especifica-1-p1" data-row="1" data-column="1">b11</button>
<button id="especifica-1-p2" data-row="1" data-column="2">b12</button>

Then you can use JavaScript

event.target.getAttribute("data-row");
event.target.getAttribute("data-column");

Upvotes: 1

Robert McKee
Robert McKee

Reputation: 21487

The easy way would be to do one of the following:

  1. Store the values of i and j on the DOM element.
  2. Parse the clicked id to get the values of i and j.
  3. Assign the values of i and j to non-global variables so that you can retrieve them later.

Method 1:

for(i=1; i<=4; i++) {
  for(j=1; j<=3; j++) {
    dom_id = "especifica-"+i.toString()+"-p"+j.toString();
    element = document.getElementById(dom_id);
    element.i = i;
    element.j = j;
    element.onclick = function() {
      console.log("you clicked ",dom_id)
      ponder[this.i-1] = 0.1 + 0.05*(this.j-1);
      console.log("ponder:",this.i,ponder[this.i-1])
      $("#"+dom_id).addClass("active");
      for(k=1; k<=3 && k!=j; k++)
        $("#especifica-"+this.i.toString()+"-p"+k.toString()).removeClass("active");
    }
  }
}

Method 2:

for(i=1; i<=4; i++) {
  for(j=1; j<=3; j++) {
    dom_id = "especifica-"+i.toString()+"-p"+j.toString();
    document.getElementById(dom_id).onclick = function() {
      i = dom_id.substring(11,12);
      j = dom_id.substring(14,15);
      console.log("you clicked ",dom_id)
      ponder[i-1] = 0.1 + 0.05*(j-1);
      console.log("ponder:",i,ponder[i-1])
      $("#"+dom_id).addClass("active");
      for(k=1; k<=3 && k!=j; k++)
        $("#especifica-"+i.toString()+"-p"+k.toString()).removeClass("active");
    }
  }
}

Method 3:

for(i=1; i<=4; i++) {
  let i1 = i;
  for(j=1; j<=3; j++) {
    let j1 = j;
    dom_id = "especifica-"+i.toString()+"-p"+j.toString();
    document.getElementById(dom_id).onclick = function() {
      console.log("you clicked ",dom_id)
      ponder[i1-1] = 0.1 + 0.05*(j1-1);
      console.log("ponder:",i,ponder[i1-1])
      $("#"+dom_id).addClass("active");
      for(k=1; k<=3 && k!=j; k++)
        $("#especifica-"+i1.toString()+"-p"+k.toString()).removeClass("active");
    }
  }
}

Upvotes: 2

Related Questions