Scott Morgan

Calgary Flash and Flex Developer

May

19

Pass parameters with the Delegate class

By scott

One of the complaints I often hear about is keeping scope when using controls and/or event listeners. One of my favourite classes is the Delegate class. This class ensures scope is kept by allowing you to specify the scope when calling a method. For example:

import mx.utils.Delegate;

class Whatever extends MovieClip {

     private var someClip_mc:MovieClip;

     function Whatever() {
          someClip_mc.onRelease = Delegate.create(this, someMethod);
     }

     private function someMethod():Void {
          trace(this);
          //this will return a reference to the movieclip that is
          //attached to the Whatever class and not someClip_mc
     }
}

Ok, that’s all fine and dandy, now what if you need to pass a paramater to the method you’re targeting. You could extend the Delegate class and allow for this, or you could write your own class that does the same thing but allows for paramaters to be passed. But really, who has time to do that! Below is the same example as above but this time I pass a paramater to the method.

import mx.utils.Delegate;

class Whatever extends MovieClip {

     private var someClip_mc:MovieClip;

     function Whatever() {
          var myDel = someClip_mc.onRelease = Delegate.create(this, someMethod);
          myDel.button = someClip_mc;
          myDel.index = 4;
     }

     private function someMethod():Void {
          var button:MovieClip = arguments.caller.button;
          var index:Number = arguments.caller.index;

          trace(button + ' has an index of ' + index);
          //this will trace out someClip_mc has an index of 4
     }
}

Now you may be wondering where the heck you would use this. Picture this, you are building a menu system from an xml document. You create buttons dynamically based on the amount of data, all buttons call the same method but the method needs to know what button was selected so it can set its selected state and it also needs to know the content id associated to the button selected so the appropriate content is loaded. Instead of having a seperate method for each content id/button or updating your code everytime the data is updated this allows you to write a completely dynamic menu system in the least amount of code.

Like I said above, this isn’t the best solution, but it is a solution to the fact the Macromedia forgot to add in the ability to pass an object along to the method being called. Good news is scope is not an issue in AS 3 so the Delegate class isn’t even needed.

9 Responses so far

This works:

var del:Function = Delegate.create(this, testArguments)(“hi”)
function testArguments (h:String):Void{
trace(h)
}

This works too:
var del:Function = Delegate.create(this, testArguments)
del (“hi”)
function testArguments (h:String):Void{
trace(h)
}

Very interesting Nicidemus, I did not realize that. Guess you learn something new everyday. I prefer another method, using AS3 where the delegate class isn’t needed anymore.

Thanks for posting this though, I’m sure others will find it very useful.

Scott

Nicidemus’s solution is cool, but it doesn’t work if you’re working with a listener method that receives an argument automatically, such as using PendingCall:

var pc:PendingCall = myWebService.myMethod(arg1, arg2);
pc.onResult = Delegate.create(this, ‘onMyMethodResult’);

function onMyMethodResult(result) {
// do stuff with result
}

Scott’s solution is better, otherwise the first argument you send using Nicidemus’s method will overwrite the result argument in the result listener. Also, Scott’s solution can be simplified further using the with statement:

var myDel = someClip_mc.onRelease = Delegate.create(this, someMethod);
with (myDel) {
button = someClip_mc;
index = 4;
}

Hi Scott,

Thanks this saved my day, but Nicidemus’s solution is not working for me ..

-sara
http://www.designscripting.com/

Hey its wors for me, thank u so much.

you rock – I am doing a menu structure as you mentioned and finding this snippet of code just saved me a great deal of time…
Thank you!

Great!

That’s exactly what I was looking for…
3 years later, you still make other people’s day!

thanks Scott!

i’m using a modification of the create function of the Delegate class. to pass parameter having a delegation of the scope.

function DelegateCreate(t:Object, f:Function,args:Array):Function
{
return function():Void
{
if ((args == undefined) || (args == null))
args=[]
var _newArgs:Array = args.concat(arguments);
f.apply(t, args);
};
}

var movie_clip.onPress=DelegateCreate(this,onPressFunc,[1,2,3,4,"cool"] )

and here is the function

function onPressFunc(arg1,arg2,arg3,arg,4,arg5)
{
//N args of any king or type that you pass using the parameter array. you would try argN+1,…argN+n to see extra defaults arguments (Xml functions for instance)

}

have a Nice day, Bye!

This has been a huge help in a class file I’ve been working on controlling sound. Kept losing focus with onSoundComplete and having zero luck tracking anything utill I googled this! Luckily this is my final large AS2 project, just wish I found this sooner! Seems you can send anything including funtions! Total life saver!

private function soundBuild(sou:Sound, att:String, rec:Boolean, mov:MovieClip, tim:Number, val:Number):Void
{
sou.stop();
sou.attachSound(att);
sou.setVolume(0);
sou.start();

var sEC = sou.onSoundComplete = Delegate.create(this, soundEndCheck);
sEC.catchAttached = att;
sEC.catchRecycle = rec;

flushChannel(mov, tim, val, null);
}

private function soundEndCheck():Void
{
var catchAttached:String = arguments.caller.catchAttached;
var catchRecycle:Boolean = arguments.caller.catchRecycle;

if(catchAttached == “_wind” && catchRecycle)
{
fxWEA.start();
}
}

Leave a comment