views:

341

answers:

4

Code Example:

var gospels : Array = ["john", "mark", "matthew", "paul"];

for each (var book : String in gospels)
{
  var loader : URLLoader = new URLLoader();
  loader.load(new URLRequest("http://example.com/" + name));

  trace(book) // outputs current value of array

  loader.addEventListener(Event.COMPLETE, function(e : Event) : void {
    trace(book); // prints paul 4 times
  });
}

How can I get the event listener to use the value of the array in the loop when the event listener's function was called? I.e. when I call trace inside the event listener's function, how can I get it to output "john", "mark", "matthew", and "paul"?

+3  A: 
var gospels:Array = ["john", "mark", "matthew", "paul"];

for each (var item:String in gospels)
{
  (function(book:String){
    var loader : URLLoader = new URLLoader();
    loader.load(new URLRequest("http://example.com/" + name));

    trace(book) // outputs current value of array

    loader.addEventListener(Event.COMPLETE, function(e:Event):void {
      trace(book); // prints paul 4 times
    });
  }(item));
}
Lior Cohen
loader.load("http://example.com/" + name); should be loader.load(new URLRequest("http://example.com/" + name));Nice solution though, not so much ugly as advanced i think.
greg
Modified the answer to reflect greg's comment. Thanks greg.
Lior Cohen
Tanks Lior, worked like a champ.
Hooray Im Helping
*bows* glad it helped.
Lior Cohen
+2  A: 

I think a more elegant way is to write a superclass of URLLoader like:

class MyURLLoader extends URLLoader {
  public var book:String;

  function MyURLLoader(aBook:String){
    book = aBook;
    super();
  }
}

And then use this class in your loop, like:

var gospels : Array = ["john", "mark", "matthew", "paul"];

for each (var book : String in gospels)
{
  var loader : MyURLLoader = new MyURLLoader(book);
  loader.load(new URLRequest("http://example.com/" + name));

  trace(book) // outputs current value of array

  loader.addEventListener(Event.COMPLETE, function(e : Event) : void {
    var myUrlLoader:MyURLLoader = e.target as MyURLLoader;
    trace (myUrlLoader.book);
  });
}

P.S. I'm currently not behind a computer with flash so I did not have the opportunity to check the code.

Vincent Osinga
Also a valid solution. +1. Note, however, that seeing as the problem is scope related, it may be slightly overkill to create an entire class when this can be solved using a closure or by separating the loop's body into another function.
Lior Cohen
I agree with what Lior said, including the +1 :)
Hooray Im Helping
+1  A: 

A variant of Michael Brewer-Davis answer, but here using the Array.forEach and in that way introducing a new variable book for each iteration:

var gospels : Array = ["john", "mark", "matthew", "paul"];

gospels.forEach(function (book: String, i: int, a: Array): void {
  var loader : URLLoader = new URLLoader();
  loader.load(new URLRequest("http://example.com/" + name));

  trace(book) // outputs current value of array

  loader.addEventListener(Event.COMPLETE, function(e : Event) : void {
    trace(book); 
  });
});
Markus Johnsson
A: 

Here's the fastest and best structured way to do it (imo):

var gospels:Array = ["john", "mark", "matthew", "paul"];

for(var book:String in gospels){ //For is faster than for each
    var loader:URLLoader = new URLLoader();
    //It's good practise to add the event listener before calling the function
    loader.addEventListener(Event.COMPLETE, loaderComplete(book), false, 0, true); 
    loader.load(new URLRequest("http://example.com/" + name));
}

function loaderComplete(book:String):Function{
    return function(event:Event):void{
        event.target.removeEventListener(Event.COMPLETE, arguments.callee);
        trace(book);
    }
}
Ancide
why do you need to explicitly remove the listener if it has only a weak reference?
Richard Haven