1

I would like to assign the jQuery click-function for all elements in an array. But additionally, I need to access the array from within the click-function. The source will hopefully make it clearer:

for (var i=0; i<mybox.myarray.length; i++) {
    mybox.myarray[i].jqelem.click(function(event, mybox) {  
        event.preventDefault();
        doStuffWithParameter(mybox);    
    });
}   

// mybox is a JavaScript object (not jQuery-element!), myarray is an array, jqelem is a jQueryelement ala $("div.myclass");

The problem seems to be with function(event, mybox), apparently that doesn't work, i.e. mybox is unknown within the function. I think I 'kind of' understand why it cannot work this way, but how can this be achieved?

PS: I'm basically just doing it to save me from typing it manually for all array-elements.

Mrchief
  • 75,126
  • 20
  • 142
  • 189
Ben
  • 15,938
  • 19
  • 92
  • 138

3 Answers3

3

Just remove the (useless) second callback function parameter named mybox.

If mybox is in scope in the outer block, it'll be in scope in the inner callback function too!

Should you need to know the appropriate value of i in the callback then you can do event registration-time binding:

for (var i=0; i<mybox.myarray.length; i++) {
    mybox.myarray[i].jqelem.click({i: i}, function(event) {  
        // use "event.data.i" to access i's value
        var my_i = event.data.i;
    });
}   

The map {i : i} corresponds with the eventData parameter in the jQuery .click() documentation.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Thank you, I didn't know that. My actual problem was related to using the `i` within the inner function tough, and ShankarSangoli's answer solved it for me. – Ben Aug 01 '11 at 19:17
1

When your click handler gets called, the first argument is the event data. jQuery doesn't pass in a second argument.

Update: Using closure to get to mybox object (notice I removed the 2nd argument)

for (var i=0; i<mybox.myarray.length; i++) {
    mybox.myarray[i].jqelem.click(function(event) { 
        event.preventDefault();
        // here's the trick to get the correct i
        (function(item) {
               return function() {
                         doStuffWithParameter(mybox.myarray[item]);
               };
         })(i);

        // you can access any object from parent scope here 
        // (except i, to get to right i, you need another trick), 
        // effectively creating a closure   
        // e.g. doOtherStuff(myarray)
    });
}

Read more on closures here: http://jibbering.com/faq/notes/closures/
and here: How do JavaScript closures work?

Community
  • 1
  • 1
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • You're misunderstanding my question. I don't want the DOM element, I want the object. ´mybox´ is a JavaScript object, not a jQuery-element! – Ben Aug 01 '11 at 19:01
  • In your update, have you just removed the 2nd parameter? Cauz that doesn't do it for me. `mybox` is then `unknown` within the function. – Ben Aug 01 '11 at 19:08
  • No it is not. I just edited my answer to explain what's going on. – Mrchief Aug 01 '11 at 19:09
  • Oh, then this must be because I'm using `doStuffWithParameter(mybox.myarray[i]);` in my actual code? So how can I solve that? – Ben Aug 01 '11 at 19:11
  • Actually, ShankarSangoli's answer explains exactly this case! – Ben Aug 01 '11 at 19:16
  • @Ben let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/2028/discussion-between-mrchief-and-ben) – Mrchief Aug 01 '11 at 19:18
  • jQuery has built-in support for passing extra data to callback handlers - see use of `eventData` in `.bind()` etc. – Alnitak Aug 01 '11 at 19:31
  • Right, but will it solve this particular problem (of loop variable and evaluation scope)? – Mrchief Aug 01 '11 at 19:36
  • @Mrchief absolutely, yes. See my answer. – Alnitak Aug 01 '11 at 19:38
  • @Ben, you can use `data` attributes but IMHO, why incur the overhead when you can solve it with plain JS? – Mrchief Aug 01 '11 at 19:42
1

You can take help of jquery data attributes

for (var i=0; i<mybox.myarray.length; i++) {
    mybox.myarray[i].jqelem.data("arrayIndex", i).click(function(event) {  
        event.preventDefault();
        doStuffWithParameter(mybox.myarray[$(this).data("arrayIndex")]);    
    });
}   
ShankarSangoli
  • 69,612
  • 13
  • 93
  • 124