DWR Callback closures inside loops

I’ve been doing a fair bit of Javascript lately. Like anytime I learn a new language I look back at code I wrote a week ago and thing OMG… what was I thinking!?

One useful thing I learnt today was how to use the DWR closure callback pattern inside a loop.

My original code looked like this:


var taggedLinks = $$(".taggedlink");

for(var i=0; i < taggedlinks.length; i++) {
	RatingApi.getRating(taggedLinks[i].href, {
		callback: function(data) {
			displayRating(data, taggedLinks[i]);
		}
	});
}

Where RatingApi.getRating(..) is a DWR AJAX call. It’s fairly clear what the problem is: the displayRating function is called when RatingApi.getRating returns. Obviously the value of i will be not what was expected.

The solution looks like this (thanks Ben!):


var taggedLinks = $$(".taggedlink");

for(var i=0; i < taggedlinks.length; i++) {
	var remoteCall = {
		index : i,
		callback: function(data) {
			displayRating(data, taggedLinks[this.index]);
		}
	};	

	RatingApi.getRating(taggedLinks[i].href, remoteCall);
}

6 Comments »

  1. Hani Suleiman Said,

    May 18, 2007 @ 11:13 am

    Yeah, I just discovered this pattern too, the dwr docs sort of hint at it, but in a fairly oblique manner, sufficiently so that you don’t feel like giving them any credit when you ‘discover’ this approach!

  2. Lav Said,

    May 6, 2008 @ 8:52 am

    Does this pattern work in DWR version 2 ?

  3. Nick Lothian Said,

    May 6, 2008 @ 4:11 pm

    I can’t see why it wouldn’t - it’s not specifically a DWR thing, more Javascript + Async calls

  4. Lav Said,

    May 7, 2008 @ 6:36 am

    Hi,

    In the following code, when I give an alert for ‘this.index’, it is displayed as undefined.

    Could you please help me.

    for(var i=0;i<ids.length;i++) {
    var remoteCall = {
    index : i,
    callback : function(data) {
    fillTable(data, ids[this.index]);
    }
    };
    PopulateParameterList.getAjaxPopulateParameterList(paramId,reportId,”",remoteCall);

    Thank you

  5. Paul Said,

    July 16, 2008 @ 9:03 am

    Lav,

    This approach doesn’t seem to work under pre v3.0 of DWR - I had the same problem - ie undefined index.

    After lots & lots of searching I eventually got it working by adapting Example 7 so that it would work from within a loop. (BTW: it also explains why the above approach doesnt work in Example 5)

    See: http://blog.morrisjohns.com/javascript_closures_for_dummies.html

    I hope someone finds this useful and it saves them some time.

    Paul

  6. Paul Said,

    July 18, 2008 @ 6:30 am

    Here is roughly how i got the looping callback to work… (this is specifically for dwr2.*)

    function newClosure(someNum, someRef) {
    return function(x) {
    showResultsInBrowser(x, someNum);
    }
    }

    function getServerResponses(){
    // some other stuff…
    var count = aJsVariableSomewhere;
    for(var k=1;k<=count;k++){
    closure = newClosure(k, {somevar : ‘closure’+k});
    remote.method(”response”+k, closure);
    }
    }

    function showResultsInBrowser(serverResponse, index){
    // do some UI stuff
    }

RSS feed for comments on this post

Leave a Comment