简体   繁体   中英

Passing a parameter into an event listener function in a loop - pass by reference javascript

I am assigning event listeners inside of a loop. I am passing a variable that changes throughout the loop into the event listener function. However I am having a problem. All of the event listeners are receiving the last value of the variable in the loop, instead of the value that I meant to send at each point in the loop. The function where I assign the event listeners is the following

let arr;
let newElem;
let id;
  for (let i = 6; i < 13; i++) {
    arr = this.state.cards[i];
    if (arr.length > 1) {
      for (let j = 0; j < arr.length; j++) {
        if (j !== arr.length-1) {
          newElem = document.createElement('div');
          newElem.id = 'p' + i + '-' + (j+1);
          document.getElementById('p' + i + '-' + 
            j).appendChild(newElem);
        } else {
          id = 'p' + i + '-' + j;
          document.getElementById(id).className = 'cardLocations 
            faceUp';
          newElem = document.createElement('p');
          newElem.innerHTML = arr[j].id;
          document.getElementById(id).appendChild(newElem);
          document.getElementById(id).addEventListener('click', () => 
            {this.selectCardsFromBoard(id)});
        }
      }
    } else {
      newElem = document.createElement('p');
      newElem.innerHTML = arr[0].id;
      document.getElementById('p6-0').appendChild(newElem);
      document.getElementById('p6-0').addEventListener('click', () => 
        {this.selectCardsFromBoard('p6-0')});
    }

The problem is that whenever I click on any of the divs that I assigned event listeners to, the function selectCardsFromBoard is called with the same value and that is the final value that 'id' reaches in the loop. I want to be able to call the function with the value that 'id' is when it is assigned. I think this is some kind of pass by reference issue but I can't figure it out.

You want your id variable to be declared within the context of your for loop. Currently you are declaring id as a global variable and by the time your event is called the loop has already ran all the way through. All you need to do to fix it is get rid of the let id;' at the top of the program and change let id;' at the top of the program and change id = 'p' + i + '-' + j; to let id = 'p' + i + '-' + j;`

That's because all event handler share the same id variable. You can either defined it inside the loop so that it is scoped per iteration, or change the event handler to

document.getElementById(id).addEventListener(
  'click',
  event => this.selectCardsFromBoard(event.currentTarget.id)
);

For more general information about the problem see JavaScript closure inside loops – simple practical example


I would probably completely remove the id variable and do

// outside the loops
const clickHandler = event => this.selectCardsFromBoard(event.currentTarget.id)

// ...
const element = document.getElementById('p' + i + '-' + j);
element.className = 'cardLocations faceUp';
element.addEventListener('click', clickHandler);
 // why is this variable defined outside of your loop?
const newElem = document.createElement('p');
newElem.innerHTML = arr[j].id;
element.appendChild(newElem);

Calling getElementById repeatedly with the same argument is unnecessary. There are probably other things that could be improved (eg you could make use of event delegation instead of assigning the same handler to so many objects), this is only focusing on the id variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM