1

I have come up with the code below. The problem is that on change every element alerts the last iteration index. For example if there are 24 items on the elements array every single element on change will alert "Changed row 23" . I kind of see why it is happening but cant find away to get around it so that every element onchange will alert its index instead of the last. Any help will be appreciated.

for (var i = 1; i < elements.length; i++) {
        elements[i].onchange = (ev: Event) => alert("Changed row " + i);
        usersTable.appendChild(elements[i]);
    }
DonO
  • 1,030
  • 1
  • 13
  • 27

2 Answers2

2

Use Array.prototype.forEach, where you can pass the index into the callback function...

elements.forEach((element, idx) => {
  elem.onchange = (ev: Event) => alert("Changed row " + idx);
  usersTable.appendChild(elem);
});

Documentation on Array.prototype.forEach can be found here

Brocco
  • 62,737
  • 12
  • 70
  • 76
  • Thank you, while this might work for the case on my question which I simplified, I am still interested for a way to do it without changing my loop. – DonO May 08 '15 at 15:14
  • Also it's not exactly equivalent, because in the original code the first element is skipped (`var i = 1; i < elements.length`) – CodingIntrigue May 08 '15 at 17:04
  • 1
    @RGraham Excellent point, that case could easily be handled with an if statement within the handler – Brocco May 08 '15 at 17:09
2

When your events are executed, the for loop would have completed. At that point i would equal whatever it was when the loop ended—elements.length - 1 (which is why it's always equal to 23 for you).

You can fix this by using Brocco's solution, but since you want to know a way of doing it without changing the loop, you will need to pass in the value of i when setting the change function. This can be achieved by using an IIFE:

for (var i = 1; i < elements.length; i++) {
    (function (i) {
        usersTable.appendChild(elements[i]);
        elements[i].onchange = (ev: Event) => alert("Changed row " + i);
    })(i);
}

Which is a longer way of expressing what the .forEach function does for you.

Alternatively, you could also use .bind:

elements[i].onchange = function(i: number, ev: Event) {
    alert("Changed row " + i)
}.bind(this, i);
Community
  • 1
  • 1
David Sherret
  • 101,669
  • 28
  • 188
  • 178