Pass parameters with the Delegate class
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
Nicidemus
October 26th, 2007
9:01 am
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)
}
scott
October 26th, 2007
9:18 am
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
william
June 18th, 2008
12:13 pm
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;
}
Saravanan
November 6th, 2008
12:31 am
Hi Scott,
Thanks this saved my day, but Nicidemus’s solution is not working for me ..
-sara
http://www.designscripting.com/
alrevez
February 8th, 2009
11:10 am
Hey its wors for me, thank u so much.
Nathan king
February 26th, 2009
8:41 am
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!
elena
July 20th, 2009
6:06 am
Great!
That’s exactly what I was looking for…
3 years later, you still make other people’s day!
thanks Scott!
j.c Pimentel
May 2nd, 2010
7:00 pm
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!
simon kinslow
September 13th, 2010
8:54 am
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