I’ve run into quite a few people wondering how to get an XML object to trigger a particular method in a class instance on load using ActionScript 2.0. In trying to accomplish this, you will encounter two issues, both of which can be circumvented.
Firstly, the scope of the onLoad function is within the method that created it, and it does not have direct access to any of the methods of the class instance. Using this. , you can explicitly access the scope of the XML object from within the handler. Many people are taking advantage of this by assigning an “owner” or “_parent” property to their XML object, then using that reference to access the class instance methods. It looks something like this:
class MyClass { var myXML; function loadData():Void { myXML = new XML(); myXML.ignoreWhite = true myXML.owner = this; //used as reference in myXML myXML.onLoad = function(p_success:Boolean):Void { this.owner.myXMLOnLoad(p_success); } myXML.load("url.xml"); } function myXMLOnLoad(p_success:Boolean):Void { trace("XML Loaded: "+myXML.toString()); } } |
This works, but the moment you try to type myXML as XML, the compiler will spit back an error. This is because XML is not a dynamic class, so you are not allowed to add new properties to its instances arbitrarily.
So, how can we strict type our myXML object, and still call class instance methods in the right scope from within our onLoad handler? The trick is to take advantage of a relatively obscure feature of function creation called the “activation object”. This allows you to access any locally scoped variables that were in existence when your function was created. In this case, we can simply define an owner variable in the loadData method, and point it back to the class instance with “this”. You can then use that reference inside your anonymous “onLoad” function to trigger the appropriate method inside the class instance. For example:
class MyClass { var myXML:XML; function loadData():Void { myXML = new XML(); myXML.ignoreWhite = true var owner:MyClass = this; //used as reference in myXML myXML.onLoad = function(p_success:Boolean):Void { owner.myXMLOnLoad(p_success); } myXML.load("url.xml"); } function myXMLOnLoad(p_success:Boolean):Void { trace("XML Loaded: "+myXML.toString()); } } |
The changes are subtle, so let’s take a quick look at them:
- I typed myXML as XML.
- Instead of creating a new property of myXML called owner, I defined a local variable called owner that references the class instance with “this”.
- In the onLoad handler, I accessed the owner variable that was made available through the function’s activation object. Notice that I did not use “this.”.
I hope this helps some people out. For a great explanation of scope, and how the activation object works, check out Scope Chain and Memory waste in Flash MX by Timothée Groleau.
XML vs. AS2 part Deux – scoping callbacks: Inheritance
That insanely smart Canuck (at least, I think he’s a Canuck; too cute not to be), Grant Skinner, has posted a neat way to utilize el activation object to quickly and easily scope your XML objects (LoadVars same way). Nestled…
I was unaware of this feature, but it brings up a couple of additional concerns for me:
First, if this works then it means all of the temporary variables declared in loadData(). In this case no big deal, but there could be cases where a large amount of useless data is retained because a function is holding it in scope.
Second, you could call an instance method of the class from inside your onLoad with a completely different scope than should be allowed and not get a compiler error. This is a MM problem, but could be painful if you forget the above solution.
Thanks for the explaination, it saved me a lot of time 🙂
Great piece of code. I was creating global refs to the parent object before. Thanks.
Nice, I’d been getting no where trying to get a callbacks working in a class.
This works a treat. Thanks