Dave Carabetta Blog Banner


July 26, 2006

Array vs. ArrayCollection in Flex 2 (with a ColdFusion Slant)


I've been spending a bit of personal time digging into Flex 2 development. One thing I've noticed up front is that there's an important distinction between using an Array and an ArrayCollection when coding your applications. This is an important point for ColdFusion developers because, in CF, we only have an Array datatype while most other languages (Java, C#, etc.) have an explicit ArrayCollection class. Further, since Flex is simply a front-end development language, you're likely to be doing lots of talking to a back-end technology to return data sets and the like.

So what's the difference? Well, the LiveDocs entry for the ArrayCollection class sums it up pretty well, so here it is:

The ArrayCollection class is a wrapper class that exposes an Array as a collection that can be accessed and manipulated using the methods and properties of the ICollectionView or IList interfaces. Operations on a ArrayCollection instance modify the data source; for example, if you use the removeItemAt() method on an ArrayCollection, you remove the item from the underlying Array.

The first sentence in that explanation is the key: The ArrayCollection class is simply a wrapper around the Array class. So if they're both Arrays at some level, why is this important? Well, with a standard Array, what you have available to you are the basic methods and properties that you'd expect in any language: push() (for adding an element to the end), pop() (for removing the last element), length (the number of indices), etc. However, the ArrayCollection class provides a suite of immensely convenient "extra" methods that can act on the Array.

For example, say I have an array with the values in the color spectrum:

var spectrumColors:Array = ["red","orange","yellow","green","blue","indigo","violet"];

(Quick side note to ColdFusion developers: Arrays in ActionScript are zero-based. So, to directly access the element "red", you'd use spectrumColors[0] rather than spectrumColors[1] like you would in ColdFusion.)

However, Stephen Hawking releases a new theory that there's no such thing as "green," and mandates that it should be removed from the color spectrum. How would you do it using the Array class? Honestly, it's not worth getting into the code because it's a waste of keystrokes. However, there's a really easy way to do this: Use the ArrayCollection class. The ArrayCollection class extends the ListCollectionView class. Without getting into the boring details, the ListCollectionView class has a bunch of extremely handy methods for manipulating its elements, namely the addItemAt(), removeItemAt(), and getItemAt() methods. Going back to our example, if the spectrumColors variable is datatyped as being an ArrayCollection, accomodating Mr. Hawking becomes immensely easier:

var spectrumColors:ArrayCollection = ["red","orange","yellow","green","blue","indigo","violet"];

spectrumColors.removeItemAt(spectrumColors.getItemIndex("green"));

All the code above does is create the spectrumColors variable of type ArrayCollection, and then removes the item from the array based on the returned index value that matches the value "green." See? Easy. No need to manually loop over the array to find an index or verbose constructs like that.

OK, so I promised a ColdFusion slant in the post title. Now that you have an understanding of Array vs. ArrayCollection, let's see how this fits in to ColdFusion and Flex.

Flex is all about providing a rich user interface for our users. However, the key phrase in that sentence is "user interface." Flex does not provide any native database connectivity, so you need a back-end technology to do the "heavy lifting" and return the results to Flex for display. The ColdFusion team did a phenomenal job of making Flex/ColdFusion integration as seamless as possible in the 7.0.2 release. However, there are certain nuances that we need to keep in mind when working between these two technologies. One such nuance is the fact that it's one thing to query for data and return it as-is to the calling environment (ColdFusion), but it's another to be able to use advanced concepts such as run-time sorting and filtering for display (Flex). To that end, certain Flex 2 framework components use what are known as data providers to not only display the result set, but to further allow the user to manipulate the results to their liking. To that end, the Flex engineers cleverly implemented these framework components such that you could either use the raw datatype returned or you could use a collection instead, which allows for more advanced access to the data set. Hopefully my above explanation regarding the difference between an Array and and ArrayCollection sufficiently shows the difference between a datatype and its Collection wrapper class. You could use a basic Array (the raw datatype) to display a result set, if that's all you want to do. But to provide more advanced interaction, these raw datatype classes don't provide the necessary advanced access or event broadcasts necessary. So you're going to need to convert the datatype that comes back from your back-end (i.e., ColdFusion) into the appropriate collection type so that it can then be used for display, thereby offering some of the more advanced features that the Flex framework provides.

While there are many controls that use data providers, I'm going to use the DataGrid in my example because that seems to be the most common way of displaying tabular data in Flex. If I want to display a datagrid consisting of some basic company information: company name, address, etc., below is the ActionScript code needed to take the returned results into the appropriate collection datatype. Assume that a ColdFusion query is being returned.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" initialize="myService.send()">

<mx:Script>
<![CDATA[
   import mx.collections.ArrayCollection;
   import mx.rpc.events.ResultEvent;
   
   [Bindable]
   private var companyInfo:ArrayCollection;
   
   private function resultHandler(event:ResultEvent):void {
    companyInfo = event.result as ArrayCollection;
   }
]]>
</mx:Script>

<mx:HTTPService id="myService" url="url/to/cfc?WSDL" result="resultHandler(event);" />

<mx:DataGrid dataProvider="{companyInfo}" />

</mx:Application>

As you can see the above code simply takes the query returned from ColdFusion ("event.result") and "coerces" it (or casts it) to an ArrayCollection using the as keyword. The framework takes care of everything else for you. Then I simply assign the companyInfo variable as the data provider for the DataGrid. If I now wanted to add more advanced functionality, such as filtering or editing, to the result set, I already have the results in the appropriate format. I just need to write a function that acts as the filter or "listens" for the updated data. The Adobe LiveDocs resource provides a great example of providing this sort of functionality.

Hopefully this provides a basic understanding of the difference between datatypes and their associated Collection classes, and when each one should be used.



Related Blog Entries

Comments
Andy Clark's Gravatar So really no reason not to create an ArrayCollection, right?
Ben Forta's blog had a useful filtering example a few days ago
Love the google ad
# Posted By Andy Clark on 7/27/06 at 6:51 AM
Sam Farmer's Gravatar Great post. Its interesting how similar all those ArrayCollection functions are to the list functions in ColdFusion!
# Posted By Sam Farmer on 7/27/06 at 9:02 AM
Dave Carabetta's Gravatar Andy, the "only" time I can think of where you'd want to use a regular array is for some sort of internal storage of some data structures where you don't care about anything more than just a simple push/pop stack, but not for the controls that need data providers. Simple arrays, in that instance, are limiting.

I should be careful and point out that "only" is in quotes because I am new to ActionScript 3 and am still getting my feet wet. That being said, in virtually all of the tutorials I've worked through, ArrayCollection has been the preferred data structure.

Sam, I caught Ben's post, and it's definitely a good example of what I was trying to do. I have to say that, so far, the LiveDocs for Flex 2 are really top notch, with both basic and advanced examples.
# Posted By Dave Carabetta on 7/27/06 at 10:30 AM
John Wilker's Gravatar Good post, well timed. A colleague and I were just talking about Arrays vs. ACs (ArrayCollection is just too long) :)


Very informative!
# Posted By John Wilker on 7/27/06 at 10:38 AM
PaulH's Gravatar thanks dave. been banging my head against the wall all afternoon over array vs arrayCollection for a CFC method that returns a cfquery. flex UI & cf backend were happily yapping away but no data was changing hands. casting event result as an arrayCollection fixed.
# Posted By PaulH on 8/3/06 at 11:10 AM
Dave Carabetta's Gravatar Paul, glad it helped. Yeah, the ArrayCollectio epiphany has been hugely important for my understanding of Flex/CF integration.
# Posted By Dave Carabetta on 8/3/06 at 11:39 PM
Jimmy's Gravatar Hello,

Just followed what you had and tried to apply that to what I'm doing. The problem is I keep getting this error msg and not sure what to do.

Cannot assign operations into an RPC Service (WSDL)

Thanks,
Jimmy
# Posted By Jimmy on 8/10/06 at 5:16 PM
ATancevski's Gravatar Thanks, Dave you cleared my things a lot, just what i need a simple explanation. Good post, take care.
# Posted By ATancevski on 10/12/06 at 10:14 PM
Rachel Maxim's Gravatar Hi Dave - Great post, thanks for putting this out there...it just happened to solve a question I was dealing with at the moment! (PS we'll miss you at Max this year!)
# Posted By Rachel Maxim on 10/17/06 at 3:11 PM
The Grand Master's Gravatar Just confirms to me that as I thought - Flex has too many redundant storage mechanisms. Adobe should spend less time inventing un-needed dp's. Also less boring OOP drivel that knowone actually uses. More time making the Flex IDE and program like Visual Basic please Adobe.
# Posted By The Grand Master on 10/19/06 at 9:47 PM
todd sharp's Gravatar "More time making the Flex IDE and program like Visual Basic please Adobe." --- OMG you must be kidding?

Dave: Interesting to note that when you return an array of structures instead of a query (which the datagrid happily will use as a dataProvider) the coercion of the result into an ArrayCollection will not work. I'm still trying to figure out why since I'd really like to filter my grid, but without using an array collection i'm going to have to get hacky with it.
# Posted By todd sharp on 11/8/06 at 10:17 PM
todd sharp's Gravatar Figured it out:

This works: myGrid.dataProvider = new ArrayCollection(event.result);

This don't work: myGrid.dataProvider = event.result as ArrayCollection;
# Posted By todd sharp on 11/8/06 at 11:05 PM
Sean Corfield's Gravatar Thanx for this post - it saved me a ton of time the other day! I searched Google, trying to figure out how to return a query from ColdFusion to Flex and this was pretty much first on the list... had me up and running in no time!
# Posted By Sean Corfield on 11/15/06 at 2:12 AM
Dave Carabetta's Gravatar Glad it could help you out Sean!
# Posted By Dave Carabetta on 11/18/06 at 5:21 PM
Emory's Gravatar The only problem with your first example is if your dataset has more then one "green" in it, then you will only remove the first instance. A more entertaining way using arrays that I just learned would be :

var spectrumColors:Array = ["red","orange","yellow","green","blue","indigo","violet"];

function remove(element:*, index:int, array:Array) : Boolean {
    return (element!="green");
}

spectrumColors = spectrumColors.filter(remove);

or even

spectrumColorsCollection:ArrayCollection = new ArrayCollection(spectrumColors.filter(remove));

if you want the best of both worlds.
# Posted By Emory on 12/2/06 at 2:28 AM
Greg Johnson's Gravatar Hi Dave,

Great post, definitely has inspired some good chatter. I have a slightly different use case that I am having a hard time figuring out and I was wondering if you had any input.

I am currently using a remoteObject to run a cfc which contains a sql query. After the query is returned, I need to do some additional data manipulation (a few simple math funtions and some formatting). I am doing this manipulation within the CFC as well and then returning those final values as a structure to flex.

Flex automatically converts the structure into an object, unlike the query with is automatically converted into an ArrayCollection. Ultimately I want to use the arraycollection for my datagrid to display the results. Is there a way to convert the object into an array collection?

Thanks,

Greg
# Posted By Greg Johnson on 4/23/07 at 11:30 PM
Anas Mughal's Gravatar Thanks for clearing the usage of Array vs ArrayCollection.
# Posted By Anas Mughal on 5/21/07 at 1:47 PM
michael's Gravatar Thanks Dave for the breakdown, it has helped me a great deal. However, while trying to implement your usage of removeItemAt the getItemIndex portion continues to return -1.

My array looks like this:
private var fields:ArrayCollection = new ArrayCollection([{fieldTag: "big", value:"t"}, {fieldTag: "small", value: "t"}]);

and the following line always yields -1, which is "out of bounds".
public function remItem():void{
fields.removeItemAt(fields.getItemIndex({fieldTag: "small", value:"t"})+2);
}

Any idea what I am doing wrong?
# Posted By michael on 6/4/07 at 7:05 AM
Dave Carabetta's Gravatar Hi Michael. I don't think getItemIndex() will work on an object like that. My example uses a simple string value, which I believe is what getItemIndex() is designed for. For your example, I think you're going to have to loop through the ArrayCollection and look for the value that you want to remove and then call removeItemAt() using the current index value of the loop. Make sense?
# Posted By Dave Carabetta on 6/5/07 at 9:51 AM

© Dave Carabetta, 2005-2008. This blog licensed under the Creative Commons License. Some rights reserved. This is a personal weblog. The opinions expressed here represent my own and not those of my employer. Blog software provided by Raymond Camden.