| 
  Introduction to XML in Flash by senocular
 
 Trouble With XML onLoad In AS2 ClassesThis is probably the biggest issue out there 
                                  for people using XML in ActionScript 2.0 classes. 
                                  This doesn't necessarily revolve around XML 
                                  so much, but rather about dealing with callback 
                                  event handlers like onLoad from within classes.
 The problem is that if you define an onLoad 
                                  event from within a class method, the onLoad 
                                  script cannot access class properties. Example 
                                  class XMLContentLoader 
                                    {
                                    public var 
                                      target_txt:TextField;private 
                                      var _xml:XML; function 
                                      XMLContentLoader(url:String, 
                                      target:TextField){
                                      target_txt 
                                        = target;_xml = 
                                        new XML();_xml.ignoreWhite 
                                        = true;_xml.onLoad 
                                        = function(success){
                                        if (success) 
                                          target_txt.text 
                                          = this.firstChild.toString(); }_xml.load(url); } } Here, the XMLContentLoader class creates instances 
                                  that loads XML from a URL string and displays 
                                  its firstChild (the full XML document) into 
                                  a textfield saved under the target_txt property. 
                                  Problem is, the onLoad can't correctly reference 
                                  the target_txt property. WHY, sweet child of 
                                  mine WHY!?! The reason for this is because once you've 
                                  entered that onLoad method, you are no longer 
                                  in the scope of the class instance. You have 
                                  now entered the scope of the XML instance. Within 
                                  this scope, when attempting to access target_txt, 
                                  you are attempting to access target_txt within 
                                  the XML instance and not the XMLContentLoader 
                                  instance. Thankfully, there are a couple of 
                                  ways around this. 1. Use a local variable. If you created the 
                                  event handler (onLoad) function within a class 
                                  method, then that function has access to all 
                                  local variables declared within that method 
                                  in which its defined. If you assign the needed 
                                  property reference to a local variable in that 
                                  host method, it will carry into the scope of 
                                  the scope of the handler giving you a valid 
                                  reference. 
                                  var txt 
                                    = target_txt;_xml.onLoad 
                                    = function(success){
                                    if (success) 
                                      txt.text 
                                      = this.firstChild.toString(); } For variable reference only; not safe for calling 
                                  class methods. 2. Define the variable within the object receiving 
                                  the handler. Since when in the onLoad the _xml 
                                  instance is looking for its own target_txt and 
                                  not the class instance's, what you could do 
                                  is just copy that variable, keeping the same 
                                  name, within the _xml instance. Then, the onLoad 
                                  would correctly resolve that variable when it 
                                  is referenced. Now, the flip side to this in 
                                  AS 2.0 is that, at least with the XML object, 
                                  that you're dealing with instances of a non-dynamic 
                                  class. This means that you cannot, technically, 
                                  add or access properties or methods that are 
                                  not defined within its class definition. You 
                                  can, however, trick Flash's compiler to ignore 
                                  this by using associative array syntax to define 
                                  your property, in this case, target_txt. 
                                  _xml["target_txt"] 
                                    = target_txt;_xml.onLoad 
                                    = function(success){
                                    if (success) 
                                      target_txt.text 
                                      = this.firstChild.toString(); } Using _xml["target_txt"] tricks the compiler 
                                  as when using [] to access variables. The compiler 
                                  can't be certain of what value is within the 
                                  brackets (it could be a variable that could 
                                  be valid or invalid) so it ignores the reference 
                                  altogether letting you get by with compiler 
                                  deceiving heathenry. When in the onLoad, target_txt 
                                  is correctly found because it is defined within 
                                  the _xml instance. To add injury to insult, 
                                  the compiler isn't smart enough to understand 
                                  this change in scope either (actual running 
                                  ActionScript knows the change, just not the 
                                  compiler creating the SWF) so as you attempt 
                                  to access target_txt in the onLoad function 
                                  without [], the compiler won't complain as it 
                                  still assumes that when you're using you're 
                                  in the scope of the class where target_txt is 
                                  a valid property. For variable reference only; not safe for calling 
                                  class methods. 3. Define a reference to the class instance 
                                  within the object receiving the handler. This 
                                  approach is a little like the previous only 
                                  this one adds a reference to the class instance 
                                  itself and not just one property. This is helpful 
                                  if you're dealing with many variables or you 
                                  need to pass the class instance itself in to 
                                  function calls within the handler function's 
                                  scope etc. Here, again, the compiler gets in 
                                  the way when dealing with non-dynamic XML instances. 
                                  There's an added complication, though, as when 
                                  using a reference in this manner, you're not 
                                  duplicating an existing class property so the 
                                  compiler will know it doesn't exist where ever 
                                  you use it. Thankfully, the compiler did learn 
                                  one thing in its limited schooling, and that 
                                  was that this-referenced properties within non-class 
                                  function definitions should go ignored. So, 
                                  within the onLoad, a class reference variable 
                                  can be left alone by the compiler if this is 
                                  used to specify that the property does in fact 
                                  belong to the object in which the handler is 
                                  being defined (of course this is a little contradictory 
                                  to some of its other behavior, but what are 
                                  you going to do). The initial class reference 
                                  when defined within the XML instance will still 
                                  need [] to be ignored by the compiler, however. 
                                  _xml["hostInstance"] 
                                    = this;_xml.onLoad 
                                    = function(success){
                                    if (success) 
                                      this.hostInstance.target_txt.text 
                                      = this.firstChild.toString(); } Note: you could also create an undefined Object 
                                  property in the class called hostInstance to 
                                  prevent the need to use this. Also, if you're 
                                  confident in your coding, you could also just 
                                  drop the typing altogether for the XML instance 
                                  preventing any of the compiler complications 
                                  mentioned above. 
                                  private var 
                                    _xml; 3.1. Combine 3 and 1. Use a local variable 
                                  to reference the class instance. This takes 
                                  away the need to a) define any extra variables 
                                  within the object getting the event handler 
                                  b) trick the compiler and c) define multiple 
                                  variables for what ever properties you wish 
                                  to reference 
                                  var host 
                                    = this;_xml.onLoad 
                                    = function(success){
                                    if (success) 
                                      host.target_txt.text 
                                      = this.firstChild.toString(); } 4. Use the Delegate Utility. Available as of 
                                  Flash 
                                  MX 2004 7.2, this is probably the most "official", 
                                  though possibly also the most confusing (and 
                                  less apparent) method. Delegate is a class in 
                                  mx.utils available to ActionScript 2.0 that 
                                  allows you to change the scope of a function 
                                  call from one object to another. Basically its 
                                  a wrapper for the functionality that function.call() 
                                  and function.apply() provide. Delegate just 
                                  makes it a little easier to intercept function 
                                  definitions in one object which are to be executed 
                                  within the scope of another. Here's a simple 
                                  example of its use. 
                                  import mx.utils.Delegate;var objectA:Object 
                                    = {name: 
                                    "object A"};var objectB:Object 
                                    = {name: 
                                    "object B"}; function getName():String 
                                    {
                                    return this.name; }objectB.getName 
                                    = Delegate.create(objectA, 
                                    getName);trace( 
                                    objectB.getName() 
                                    ); // 
                                    traces "object A"; Here, the static method create is used off 
                                  of the Delegate class to create a function (getName) 
                                  that is assigned to object B but, when run, 
                                  is run in the scope of object A. This means 
                                  that any instance of 'this' in that function 
                                  will refer to object A instead of object B even 
                                  though it is being called from object B. This can then be applied to the XML example 
                                  were we could have the onLoad be run in the 
                                  scope of the class thereby making all references 
                                  to class properties valid as the call would 
                                  be within the scope of the class instance and 
                                  not the XML object. For the sake of simplicity, 
                                  we'll make the function to be used in the onLoad 
                                  a method of the class. This is not uncommon 
                                  to do anyway. Here, it makes the assignment 
                                  using Delegate.create() a lot easier. Here is 
                                  the full modified class: 
                                  import mx.utils.Delegate;class XMLContentLoader 
                                    {
                                    public var 
                                      target_txt:TextField;private 
                                      var _xml:XML; function 
                                      XMLContentLoader(url:String, 
                                      target:TextField){
                                      target_txt 
                                        = target;_xml = 
                                        new XML();_xml.ignoreWhite 
                                        = true;_xml.onLoad 
                                        = Delegate.create(this, 
                                        onLoadEvent);_xml.load(url); } function 
                                      onLoadEvent(success:Boolean):Void 
                                      {
                                      if (success) 
                                        target_txt.text 
                                        = _xml.firstChild.toString(); } } First, in order to use Delegate, at least by 
                                  its short name, import is used to bring it in 
                                  from mx.utils.Delegate (otherwise, you'd have 
                                  to run it as mx.utils.Delegate.create()). That 
                                  happens above the class definition before anything 
                                  else. Then, in the constructor you can see it 
                                  being used in defining the onLoad event for 
                                  the _xml XML instance. It takes two arguments, 
                                  an object and a function. The object is the 
                                  object in which the function is going to be 
                                  run. Since we want the onLoad to run within 
                                  the scope of the class, this is passed in (representing 
                                  the class instance) as the object. The function 
                                  is the class's own onLoadEvent function defined 
                                  below. It now, when run, will correctly reference 
                                  target_txt as a property of the class without 
                                  any trouble. Of course, you can also see that 
                                  because the scope of the onLoad method is no 
                                  longer within the XML instance and this represents 
                                  the class, _xml has to be used in order to access 
                                  content of the XML instance and what had been 
                                  loaded. Note: If you use a method for your onLoad event 
                                  that is defined as a method within the class 
                                  like the onLoadEvent method above, then options 
                                  1 and 3.1 which use local variables, would not 
                                  be a valid solution for the scoping problem. 
   |