asfunction: Definition, Call Paths, and Scope

For anyone unfamiliar with asfunction I will explain the basics first. For those already comfortable with it, but want to understand how to resolve it’s call path and scope to a class instance, feel free to skip to the latter part of this article.
What is asfunction?

To quote the Flash docs it is:

“a special protocol for URLs in HTML text fields. In HTML text fields, text can be linked using the HTML A tag. The HREF attribute of the A tag contains a URL that can be for a standard protocol such as HTTP, HTTPS, or FTP. The asfunction protocol is an additional protocol that is specific to Flash, which causes the link to invoke an ActionScript function.”

This basically means that you can have a HTML textfield with a link that calls functions in Flash.

Basic asfunction Example:

function testASFunction(sParam:String):Void
{
trace("testASFunctioncalled with parameter " + sParam);
}
 
this.createTextField("foo_txt", this.getNextHighestDepth(), 0, 0, 200, 100);
foo_txt.autoSize = true;
foo_txt.html = true;
foo_txt.htmlText = "<a href="http://www.kennybunch.com/blog/wp-admin/asfunction:testASFunction,testParam">test asfunction</a>";

In the example you will notice that the protocol syntax requires a function with it’s parameter to be seperated by a comma. The protocol is limited in that your function can take only one parameter, a string. However, you can create multiple parameters by having your single string actually contain multiple parameters seperated by some sort of delimiter like “param1|param2|param3”, and upon receiving a delimited string, your function can split the values out into an array of strings like sParams.split(“|”);

Resolving asfunction Call Paths

Where an asfunction’s call path begins is quite simple, it starts on the MovieClip that the TextField with the asfunction is defined in. Therefore, you can define a call 3 ways:

1. No path defined: “asfunction:testASFunction” -> calls testASFunction on the host mc
2. Relative path: “asfunction:_parent.testASFunction” -> calls testASFunction on the parent of the host mc
3. Absolute path: “asfunction:_root.testASFunction” -> calls testASFunction on the _root

asfunction Scoping

The asfunction is like any other function call, it is scoped to the Object the Function it calls is defined on. If I call asfunction:_root.obj.testASFunction, where obj is an Object with the method testASFunction then the call will scope to obj. To illustrate, the following code correctly traces out this.prop.

var obj:Object = {};
 
obj.prop = "foo";
 
obj.testASFunction = function(sParam:String):Void
{
trace(this.prop);
}

Resolving asfunction Call Paths and Scope to Class instances

Getting your asfunctions calls to reference back to a method of (this) Object in it’s scope in an OO architecture, depends on how the TextField is used in the instance it is in. If your class (is a) extends a MovieClip and the TextField resides in the timeline of that MovieClip, there are no issues, because the call path can be scoped back to the class instance. For example, if I define the TextField directly on the MovieClip the asfunction call references the method directly in my Class:

class TestASFunctionMC extends MovieClip{
 
    private var foo_txt:TextField;
    public function TestASFunctionMC(){draw();}
 
    public function draw():Void
    {
        createTextField("foo_txt", getNextHighestDepth(), 0, 0, 200, 100);
        foo_txt.autoSize = true;
        foo_txt.html = true;
        foo_txt.htmlText = "<a href="http://www.kennybunch.com/blog/wp-admin/asfunction:testASFunction,testParam">test asfunction</a>";
    }
 
    public function testASFunction(sParam:String):Void
    {
        trace("testAsFunction called with parameter " + sParam);
     }
}

NOTE: if in the previous example the TextField was not defined directly on the MovieClip’s timeline that you are writing the class for, it needs to be resolved using relative path’s. For example, a TextField that is nested in a MovieClip inside of the MovieClip class you are defining should call “asfunction:_parent.testASFunction” to get back to your instance’s testASFunction method.

The only issue really exists when a Class (has a) uses a TextField by composition and does not extend (is) a MovieClip. In this scenario, the call is going to scope to the TextField’s host MovieClip, which in turn needs to know how to reference back to your class instance. With a little help of the mx.utils.Delegate you can resolve this call. In the following example, you will see that you just declare the function on the MovieClip that the TextField will look to, and define that function with a Delegate that marshalls the call back to your class instance.

import mx.utils.Delegate;class TestTxtContainer{
 
private var __txtField;
 
public function TestTxtContainer(oTxt:TextField)
{
__txtField = oTxt;
__txtField.htmlText = "<a href="http://www.kennybunch.com/blog/wp-admin/asfunction:_parent.testASFunction,testParam">test asfunction</a>";
__txtField._parent.testASFunction = Delegate.create(this, testASFunction);
}
 
public function testASFunction(sParam:String):Void
{
trace("testAsFunction called with parameter " + sParam);
}
}

As you can see, this an implementation detail that causes the issue. If you never use this type of scenario in your architecture, it won’t effect you. Although, in the case that you run into a design decision where a (has a) TextField in a non MovieClip based class is the better implementation choice, this is one way to solve your dilema .

Hopefully, this gave you a little more insight into how the asfunction protocol works and how you can use it in your architecture.

5 comments

  1. Bazard

    hello, just a quick remark to let people that there is a parameter limitation in the number of characters (127).
    It is not described in the documentation but you can see it from this technote.

  2. Raff

    asfunction also works fine within the .url property of a TextFormat class, so you don’t have to use HTML. Remember to set the the .html flag to TRUE in the TextField, otherwise links will be ignored.

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">