23

For example, I have 10 a tags generated from an AJAX response:

<a href="#" id="b1">b1</a>
<a href="#" id="b2">b2</a>
<a href="#" id="b3">b3</a>
<a href="#" id="b4">b4</a>
<a href="#" id="b5">b5</a>
<a href="#" id="b6">b6</a>
<a href="#" id="b7">b7</a>
<a href="#" id="b8">b8</a>
<a href="#" id="b9">b9</a>
<a href="#" id="b10">b10</a>

I need to assign onclick event to each of them via loop:

for(i=1; i<11; i++) {
    document.getElementById("b"+i).onclick=function() {
        alert(i);
    }
}

This doesn't work, it only assigns onclick to the last a tag and alerts "11". How can I get this to work? I'd prefer not to use jQuery.

4
  • You should call attachEvent / addEventListener (although they won't solve your problem) Commented Jun 26, 2011 at 23:23
  • @SLaks Why are attachEvent/addEventListener more appropriate than element.onclick? Commented Oct 19, 2012 at 19:11
  • @MicahHenning: To allow you to have multiple handlers. Commented Oct 19, 2012 at 19:12
  • @SLaks Ah, good point. Thanks. Commented Oct 22, 2012 at 14:53

3 Answers 3

41

All of your handlers are sharing the same i variable.

You need to put each handler into a separate function that takes i as a parameter so that each one gets its own variable:

function handleElement(i) {
    document.getElementById("b"+i).onclick=function() {
        alert(i);
    };
}

for(i=1; i<11; i++) 
    handleElement(i);
Sign up to request clarification or add additional context in comments.

1 Comment

test.html:11 Uncaught TypeError: Cannot set property 'onclick' of null
20

A closure is what you're looking for:

for(i=1; i<11; i++) {
    (function(i) {
        document.getElementById("b"+i).onclick=function() {
            alert(i);
        };
    })(i);
}

3 Comments

I'd say that Caballero has a closure where they don't want one and that they want a closure buster to force the immediate evaluation of i. That's what your self-executing function is doing.
Closure/No-Closure... I don't care! This anonymous/self-invoking solution is beautiful :) I'd have ticked this one.
Far more elegant than having a separate function.
6

There are two ways to use closure on this problem. The idea is to create a scope with a snapshot of "i" variable for each iteration to be used by event handler.

Solution #1 (as was mentioned by Kevin):

for(i=1; i<11; i++) {
    (function(num) {

       document.getElementById("b"+num).addEventListener('click', function() {
            alert(num);
       });

    })(i);
}

Solution #2:

for (i=1; i<11; i++) {
    document.getElementById("b"+i).addEventListener('click', (function(){
        var num = i;
        return function() {
            alert(num);
        }
    })());
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.