AS3 - do functionClassA.call() in a functionClassB with parameters - actionscript-3

I read this : http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Function.html
But that does not exactly correspond to what I want to do, and I can't find the right solution. However my question is not so complicated.
Here is the situation :
mains.as contains a functionA(strParam:String)
onlineClass.as contains a functionB working like this :
private static functionB (fnParam:Function):void //my fnParam is functionA
{
var strParam:String = getSomeStringResult();
//I have a result from a function
fnParam.call(strParam);
//I want to execute functionA with strParam as parameter
}
But I don't understand what I have to do with call parameters.
I tried :
fnParam.call(null, strParam);
But it returns an error :
[Fault] exception, information=TypeError: Error #1009: Impossible to access a property or a method of a null object's reference
I am sure the answer already exists somewhere but a search with "function" and "call" leads nowhere.
Thank you for the help.

If a parameter is a function then you can call it directly as the parameter name if it's being passed to another function:
functionB(fnParam:Function){
fnParam('strParam');
}
The issue here looks like like the functionA is null when it's being passed through to functionB. This is possibly because they're in different files / classes but you'll probably want to debug before functionB is called to make sure functionA is accessible.

Ok, I made my code working, and I think it could be a static story. FunctionA is not static, and when I pass it as a parameter of the static FunctionB, this works :
private static var functionACallback:Function;
public static functionB( functionA:Function ):void
{
functionACallback = functionA; //set the static functionACallback
var strParam = getSomeStringResult(); //get the string
functionACallback(strParam); //call the static var with parameter
}
I don't entirely understand the issue here, but the above code resolve the problem.
defenestrate.me's answer was helpful.

Related

AS3: Using Instance Variables as Default Parameter Values

I am trying to use an instance variable as a parameter value in a method, but it is giving me an error. "Parameter initializer is unknown or is not a compile-time constant"
I want to use a non-constant instance variable though, and I assume there has to be some way around this besides calling this method from another method. Here is the code I'm referring to:
public function attack(target:Fighter=this.target):void {
}
What about:
public function attack(target:Fighter):void
{
if(target == null)
target = this.target;
}
and to be honest maybe it's easier to name one of variables _target to avoid confusion. You can use target = _target; instead of this..
You cannot set an optional parameter that way. You can set optional parameters to a default value but not a reference. In this case if you want to keep it optional you could do something like this (or what #George Profenza suggested):
public function attack(target:Fighter=null):void {
target = target ? target : this.target;
}
I see that you marked a correct answer already, but I'll explain that since you are defaulting any null parameters to this.target you would benefit from using this solution so you don't have to pass null each time you call attack() i.e. - you can do attack() instead of attack(null).

Weird behavior of Red5 service parameters called from Actionscript

I have a Red5 service function that receives a single string as a parameter, and another function that takes no parameters, like the code below:
public class AService
{
private String someName;
public void setName(String aName)
{
someName = aName;
}
.
.
public String makeMessage()
{
return("Hello, "+someName);
}
.
.
other functions
}
I also have an ActionScript function that calls the service function, using the dynamic parameter:
public class Connector
{
private var netConn: NetConnection;
public function invokeCall(theFunc:String,...theParams): void
{
var resp:Responder = new Responder(checkResult);
netConn.call(theFunc,resp,theParams);
}
.
.
}
I am aware that the "...theParams" is actually an array of parameter objects. I also know that the NetConnector class' call() method uses that parameter object array. Unfortunately, when I do an invokeCall() on my service's makeMessage() method (without putting in a parameter) like so:
invokeCall("AService.makeMethod");
I get a function nonexistent message from Red5. The only way I can make it work is to create two invoke methods, one with parameters and one without, and call that function without parameters.
Furthermore, calling my setName() function, like so:
invokeCallwithPrams("AService.setName","factor3");
doesn't seem to work unless I change the signature of my service function:
public class AService
{
private String someName;
public void setName(String[] aName)
{
someName = aName[0];
}
.
.
public String makeMessage()
{
return("Hello, "+someName);
}
.
.
other functions
}
which I don't mind (even though the Red5 documentation indicates that I shouldn't have to treat the parameter as an array), except that when I pass the string "factor3" into the NetConnection class' call() method, somehow it becomes "[factor3]" in setName()!
Obviously, something is screwy here, but I haven't been able to figure it out.
I am using Red5 Version 1.0.1 and my Actionscript is Version 3.
Can anyone explain to me what is going on and (more importantly) how to fix this???
If so, please advise...
UPDATE: The weirdness continues
I did a test in which I changed the parameter of the function I used to set up and invoke the NetConnection class' call() method. Instead of passing it a "...theParams", I changed it to theParams:String, like so:
public function invokeCall(theFunc:String,theParams:String): void
{
var resp:Responder = new Responder(checkResult);
netConn.call(theFunc,resp,theParams);
}
Interestingly, the brackets that appear in my service method setName() go away!
Whatever this problem is, it has something to do with the dynamic parameters in Actionscript. I suspect that I have found a bug in Actionscript 3 that does not allow it to properly handle dynamic parameters that are passed to a method from another method.
Has anyone else seen this problem? Is there any solution? The dynamic parameters are supposed to allow anyone to add parameters as necessary and make them any object that is necessary. Unfortunately, it doesn't look like you can use dynamic parameters passed from another method without them being screwed up.
This looks like a serious bug in Actionscript. Am I correct?
Someone please advise...
I found the solution. It is not a bug in Actionscript, it is a bit of strangeness in the language.
The basic information about the solution can be found here:
AS3 variable length argument expand to call another function with var length args
Based on what is there, I needed to do the following in the method I am using for invokeCallwithParams:
.
.
var conn:Connector = new Connector();
private function invokeCaller(fName:String,...cParams)
{
cParams.unshift(fName);
conn.invokeCall.apply(conn,cParams);
}
This eliminates the unnecessary brackets passed into my setName() service function, meaning that I can pass dynamic, variable length parameters from one method to another...

flex4 calling a function in addEventListener with dynamic suffix

I would like to call a function name from inside an addEventListener dynamically based on function parameter.
calling with newMod("moduleA", "A"); however I am getting error TypeError: Error #1006: value is not a function.
Any suggestions on how I can call this function dynamically. I have seen some answers around using an instance[function]() but am not sure how that applies with the listener,
public function newMod(mdLd,evtTyp,param):void {
info = ModuleManager.getModule(mdLd);
var mevth:String = ("modEventHandler"+(evtTyp));
info.addEventListener(ModuleEvent.READY, function(e:ModuleEvent){
this[mevth](e, param)});
info.load(null, null, null, moduleFactory);
}
private function modEventHandlerA(e:ModuleEvent):void {
vg1.addElement(info.factory.create() as IVisualElement);
}
[EDIT]
looks like changing the call to this[mevth]() works, but I cant seem to pass additional params as needed i.e. this[mevth](parm), any suggestions welcome.
I have also updated the listener to include a function call but still no joy
When you create closure "this" doesn't point to real instance "this". You can write something like this
public function newMod(mdLd,evtTyp,param):void {
info = ModuleManager.getModule(mdLd);
var self:Object = this;
var mevth:String = ("modEventHandler"+(evtTyp));
info.addEventListener(ModuleEvent.READY, function(e:ModuleEvent){
self[mevth](e, param)});
info.load(null, null, null, moduleFactory);
}
...
But I really don't recommend you write code like this.
To awnser your comment:
Function closure means that a function remembers the context in which it has been created. In your code the following line creates a closure:
info.addEventListener(ModuleEvent.READY, function(e:ModuleEvent){
this[mevth](e, param)});
The event handler function is created in the context of the class that contains the method public function newMod(mdLd,evtTyp,param):void, so your handler has access to all members of the class. This includes variables declared in the surrounding method, the private variables/methods of the class and the protected variables/method in the whole inheritence chain of the class.
The problem with the this as Ivan Dyachenko wrote is that your handler function actually is an instance of the top-level class Function. So, if you try to call a method on this in a Function object it will be the same as calling a method in any other object - this refers to the object. In your case this will be the Function object. But your function doesn't have the method you want to call on it.
Additionally you will run into another problem with your code. Because you create the event handler inline - directly as argument of addEventListener() you will be unable to remove the event listener later. You should either use the useWeakReference parameter on addEventListener() as described here or store the handler function in a variable to hold a reference on it to remove it later with removeEventListener().

AS3 Access the methods of a dynamically created movieclip

How do I access the methods of a dynamically created movieclip/object?
For simplicity sake I didn't post code on how I dynamically created the movieclip. Instead, assume its already created. It is an object. It is called field_2. Below it is referenced by using getChildByName('field_' + field.id);
Check_box_component.as
public var testVar:String = 'test';
public function testReturn()
{
return 'value returned';
}
Main.as
var temp:MovieClip = MovieClip(getChildByName('field_' + field.id));
trace(temp);
trace(temp.testReturn);
trace(temp.testVar);
Output:
[object Check_box_component]
function Function() {}
test
When I trace temp.testReturn, why does it show "function Function() {}" instead of "value returned"?
This link below helped me get this to this point.
http://curtismorley.com/2007/06/13/flash-cs3-flex-2-as3-error-1119/
have you tried:
trace(temp.testReturn());
... instead of your
trace(temp.testReturn);
... ?
I think you will have the result you are waiting for.
Actually, when doing "temp.testReturn", you are not calling the function. You need to add the parenthesis to make the actual call.
When you make a trace of temp.testReturn, the function is not executed: the trace function tell you the type of temp.testReturn, which is here correctly returned as a "function" type.
There is a difference between a function reference and a function call. Parenthesis '()' are an operator sign of ActionScript. They tell the compiler "please try to make a call to what was just behind us". Or at least I hope they are that polite.
A function in ActionScript is an object, like all other stuff. A member of Function class. You can pass it's reference back and forth, you can even call it's methods like call() or apply().
If you want a call, and not a reference, you have to use call operator.
trace(temp.testReturn());
EDIT You accepted an answer while I was typing, sorry for a duplicate answer.

Generic way to get reference to a method's caller?

I have 2 classes representing 2 objects. From the "whoCalledMe" function, I want to find out what object called the function (without passing that information in as an argument). I've used a make-believe property, "caller", that would give me the reference I'm looking for. Is there a generic way I can get a reference to the caller from there?
package {
public class ObjectCallingTheFunction {
public var IDENTITY:String = "I'm the calling function!";
public function ObjectCallingTheFunction() {
var objectWithFunction:ObjectWithFunction = new ObjectWithFunction();
objectWithFunction.whoCalledMe();
}
}
}
package {
public class ObjectWithFunction {
public function whoCalledMe ():void {
trace(caller.IDENTITY); // Outputs: "I'm the calling function!"
}
}
}
It would help to know why you need this, because I have a feeling that you don't really. If the method is anonymous, you can bind the 'this' keyword by using .apply on the method:
var foo:Function = function(arg:int):void
{
trace(this);
};
var bar:Object = {
toString: function():String { return "bar"; }
};
var baz:Object = {
toString: function():String { return "baz"; }
};
foo.apply(bar); // <-- Prints "bar"
foo.apply(baz); // <-- Prints "baz"
If the method is an instance method method however, it's a bound method and thus "this" will always point to the instance of the class it's declared in, no matter if you redefine it by using the apply method. If it's a static method, "this" doesn't make sense and the compiler will catch it.
Other than that, there's really no way short of declaring it as a parameter. There used to be a caller property on the arguments object, but it was deprecated when AS3 was released. You can get a reference to the function itself through arguments.callee, but that's not really what you asked for.
In AS3 you can throw an error and then parse the Stack Trace to find out detailed informations.
You can check here for an example:
http://www.actionscript-flash-guru.com/blog/18-parse-file-package-function-name-from-stack-trace-in-actionscript-as3
If you want to find the called function's name you can follow this example:
http://www.flashontherocks.com/2010/03/12/getting-function-name-in-actionscript-3/
I guess you want to know the caller in debug purpose. if so I would recommend setting a breakpoint in the method/function instead of tracing. When the code breaks you can backtrace the caller and a lot more. Works in Flash IDE as well as Flashbuilder. Google "as3 breakpoints" if you are new to breakpoints.
Here is the official Adobe article on using arguments.callee
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/arguments.html
It includes sample code.
Hope this helps.