views:

267

answers:

1

Gentlepersons,

How does one initialize a collection instance from MXML in Flex/Actionscript?

Background

Let's assume that:

  • I've got three lists of number-name pairs.
  • The contents of each list never changes, but I may want to add new lists in future.
  • The user can choose which list to use.

I know how to use MXML to define/initialize a Flex UI component, but that is the full extent of my XML experience.

Problem

How do I write a combination of XML declarations and Actionscript classes such that I can initialize each of my three lists from XML?

Please note that I am not trying to populate a Flex UI element (such as a DataGrid) with the various number-name pairs. I'm just trying to read the data into a plain old vanilla collection. (Once I've got my collections initialized, I can populate DataGrids or whatever at my leisure.) I can't find any documentation of how to address this super-simple case. The documentation all assumes that I'm trying to do something much more complicated, such as accessing a remote database, which confuses the issue tremendously.

Thanks! :-)

Jim Plamondon, Texas

+1  A: 

Hey there,

There's a few ways you can do this:

Sample data set:

<?xml version="1.0" encoding="UTF-8"?>
<events type="array">
    <event>
        <date>12-50-99</date>
        <title>Event A</title>
        <location>San Diego, CA</location>
    </event>
    <event>
        <date>12-50-99</date>
        <title>Event B</title>
        <location>Healdsburg, CA</location>
    </event>
</events>

Flex 4

XML Declarations

Below are 3 ways to get data into XML or an ArrayCollection, both of which you can pass to your data provider.

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx">

    <fx:Declarations>
        <fx:XML id="data" source="events.xml"/>

        <fx:XML id="data2">
            <event>
                <date>12-50-99</date>
                <title>Event A</title>
                <location>San Diego, CA</location>
            </event>
            <event>
                <date>12-50-99</date>
                <title>Event B</title>
                <location>Healdsburg, CA</location>
            </event>
        </fx:XML>

        <fx:Declarations>
            <mx:ArrayCollection id="data3">
                <fx:Object date="12-50-99" title="Event A" location="San Diego, CA"/>
                <fx:Object date="12-50-99" title="Event B" location="Healdsburg, CA"/>
            </mx:ArrayCollection>
        </fx:Declarations>
    </fx:Declarations>

    <!-- then your views -->
    <mx:Button/>
</s:Application>

Flex 3 works the same, but you just remove the <fx:Declarations/> tags.

If you want the data to be dynamic, I would just create a property for your ArrayCollection or XMLListCollection in the <mx:Script/> block in your view, say [Bindable] public var myData:ArrayCollection;, and load the data into that via XML. By keeping your data external (not hardcoding/embedding data into MXML), you don't have to recompile, and it's easier to add more and more.

In order to do that, you'd either need to use URLRequest or HTTPService. HTTPService is basically an MXML wrapper around the URLRequest.

Something like this pseudo code:

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    initialize="loadData()">
    <fx:Script>

        import mx.collections.*;

        [Bindable] public var list1:IList;
        [Bindable] public var list2:IList;
        [Bindable] public var list3:IList;

        public function loadData():void
        {
            eventsService.load(); // loads, may take a few frames/seconds
        }

        public function updateData(result:Object, property:String):void
        {
            // this["list1"] = xml;
            this[property] = new XMLListCollection(result);
        }

    </fx:Script>

    <fx:Declarations>
        <mx:HTTPService id="eventsService"
            url="events.xml" 
            resultFormat="e4x"
            result="updateData(event.result, 'list1');"
            fault="trace('eventsService Error');"/>
    </fx:Declarations>

    <!-- then your views -->
    <mx:List dataProvider="{list1}"/>
</s:Application>

Let me know if that works.

viatropos
I think this is what I was looking for. If, in the data3 initializer, I use <f:Foo... instead of <fx:Object... (where Foo is a subclass of Object defined in namespace f) then we're golden. I'll try that out.Thanks! :-)
Jim Plamondon
I don't get it.What type/class of object being instantiated in your first example (the external XML file) or second example (the in-line XML)? Neither example ever refers to a definition of what an "event" is, for example. Where did "event" come from? Does your example assume that it has been defined somewhere? Or is it of class Object, with date, title, and location being the keys of key-value pairs?Why instantiate untyped data?With apologies for being dense, and much appreciation for your attempts to enlighten me (and those who lurk behind me), I amRespectfully,Jim PlamondonTexas
Jim Plamondon
sorry about that, the xml objects are all dynamic, but you can convert those to typed classes if you manually process the xml. Assume that if you don't manually process the xml yourself, and just pass it to a dataProvider, flex will convert it to a dynamic object (ObjectProxy, if resultFormat is the default, not e4x). Both ObjectProxy and Object are basically just hashes of key-value pairs. Did this answer your question?
viatropos
Aha -- I think I've got it.In summary, leaning heavily on your answer, to read in typed XML data dynamically, I must:1. Load the *untyped* data from an external XML file via an URLRequest or HTTPService (as shown in your answer above), and then2. Write an event handler function for the HTTPService "result" event that copies the untyped XML data to appropriately-typed objects and their appropriately-typed properties.I'll go try that out.Thanks! :-) Jim
Jim Plamondon
perfect. If you are perhaps using ruby for your server-side stuff, check out RestfulX. They have a very advanced xml parser that does exactly this so you wouldn't have to write it. Good luck!
viatropos
OK, everything works as advertised, so I have marked this question as "answered" by your answer.-------With sincere appreciation for your assistance, and with hopes of "paying it forward" in future, I am---------Yours Respectfully,---------Jim Plamondon
Jim Plamondon