0

How can I reorganise the code below so the trace commands output i for each element in the photourls array and not just the last element? In a 6 element array, the trace(i); line outputs 5,5,5,5,5,5 rather than 0,1,2,3,4,5.

for (var i in photourls) {
    loaders[i] = new Loader();
    var img:URLRequest = new URLRequest(photourls[i]);
    loaders[i].load(img);
    addChild (loaders[i]);
    loaders[i].contentLoaderInfo.addEventListener(Event.COMPLETE, function(e){
                trace(i);
                trace(loaders[i]);
            });
}

Thanks a lot

2 Answers 2

2

The problem is with this code here:

loaders[i].contentLoaderInfo.addEventListener(Event.COMPLETE, function(e){
            trace(i);
            trace(loaders[i]);
        });

Because "i" will continue to alter throughout the course of the surrounding loop, only the final value of "i" will be used here. I suggest this change:

// place this outside of the loop.
function independantTrace( ...args:Array ):Function
{
    return function( ...a:* ):void{trace( args.join( "\n" ) );}
}

loaders[i].contentLoaderInfo.addEventListener(Event.COMPLETE, 
                                              independantTrace(i,loaders[i]));

That will bind the function to values of i and loaders[ i ] at that moment in the loop instead of to the "i" variable.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes this is what I was after - thanks @cwallenpoole (I've seen something like this before but couldnt remember the syntax). How exactly does it work? Could you post a simplified version of the independantTrace function without the dynamic parameters just so I can see the logic?
2
// list of photo urls
var photourls:Array = [/* ??? */];

// vars
var vars:Array = [];
var count:uint = 0;

// loop vars
var info:Object;
var ldr:Loader;
var img:URLRequest;

// load images in list
var i:String;
for each(i in photourls)
{
    ldr = new Loader();
    img = new URLRequest(i);

    /**
     * DEFINE YOUR VARS IN THIS OBJECT
     * -------------------------------
     */
    info =
    {
        target: ldr.contentLoaderInfo,
        url: i,
        counter: ++count,
        other: img
    };

    vars[vars.length] = info;

    ldr.load(img);
    addChild(ldr);

    ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, _complete);
}

// complete event
function _complete(e:Event):void
{
    var t:LoaderInfo = LoaderInfo(e.target);

    // find storage object
    var object:Object;
    for each(object in vars)
    {
        if(object.target == t) break;
    }

    // example trace of info
    trace(object.url);
    trace(object.counter);

    t.removeEventListener(Event.COMPLETE, _complete);
}

The above is an extremely messy example, I'd create your own loader class that has its own variables that you want to track and set those variables when you create your loaders. I'll do an example.

Your MyLoader class:

package
{
    import flash.display.Loader;
    import flash.events.Event;
    import flash.net.URLRequest;

    public class MyLoader extends Loader
    {
        // vars
        private var _url:String;
        public var id:uint;

        /**
         * Loads an object
         * @param url The URL to the object to load
         */
        public function myLoad(url:String):void
        {
            var req:URLRequest = new URLRequest(url);
            load(req);

            contentLoaderInfo.addEventListener(Event.COMPLETE, _complete);

            _url = url;
        }

        /**
         * Load complete
         */
        private function _complete(e:Event):void
        {
            contentLoaderInfo.removeEventListener(Event.COMPLETE, _complete);

            trace(id, url);
        }

        /**
         * Getters
         */
        public function get url():String{ return _url; }
    }
}

And then looping through your list and creating these:

var photourls:Array = [/* ??? */];

var ldr:MyLoader;
var id:uint = 0;

var i:String;
for each(i in photourls)
{
    ldr = new MyLoader();

    ldr.id = ++id;
    ldr.myLoad(i);

    addChild(ldr);
}

5 Comments

Thanks @Marty but its not quite what Im looking for. I need know how to pass variables from the for loop to the oncomplete function.
That's quite a lot of code but quite a simple workaround. I'll give it a shot. Thanks :)
It's extremely messy to be honest, a much neater way would be to make your own loader. Do you want me to do an example of that for you?
Thanks @Marty - Very simple and makes perfect sense. If it was a big project I'd defiantly go this road. I might stick with the quick and dirty method for the moment tho. Cheers for the help!
No worries, like you said; keep this in mind when you're working on larger applications. The other advantage is that you can re-use the class across applications as well :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.