Pages

March 13, 2009

ArrayCollection Basics

Posted by Jeremy Mitchell
Arguably one of the most useful constructs available to a Flex developer is an Array. Designed to store data of various types accessible via a numbered index, the Array class provides a useful mechanism for data storage and retrieval.

As such, an Array would appear to satisfy the data provider needs of any list-based control. However, it does not. Incompatibility with data binding makes an Array a poor choice of data provider. Fortunately, Flex provides a suitable alternative - ArrayCollection. An ArrayCollection provides all the features of an Array plus more.

To understand an ArrayCollection, one must first understand an Array.

Array

From Wikipedia, an Array "is a data structure consisting of a group of elements that are accessed via indexing". Arrays can store simple data types (primitives) such as number, boolean or string or complex data types such as other Arrays or objects.

In fact, Arrays defined in ActionScript (or MXML) are not strongly-typed and can store various types of data.

private var myArray:Array = new Array();
myArray[0"Tom"// string
myArray[12// number
myArray[2new Object()// object
Array elements can be retrieved or set using array access notation utilizing the zero-based index value of the desired element.

// retrieving the value of an array element
private var name:String = myArray[0];

// setting the value of an array element
myArray[0"Bill";
Note: Arrays are designed to use a numbered index. If you intend to retrieve data via a named index (i.e. Associative Array or HashMap), you may want to consider using an object as a data container. Unlike other classes, the Object class is dynamic - meaning arbitrary properties can be added to serve as keys.

var myObject:Object= new Object();
myObject.name = "Tom";
myObject.age = 27;
If your HashMap keys include spaces, use array access notation.

var myObject:Object= new Object();
myObject["first name"]"Tom";
HashMap values can be retrieved or set using dot notation (if no spaces in the key) or array access notation.

// retrieving the value of an object via an named index using dot notation
private var name:String = myObject.name;

// setting the value of an object property using dot notation
myObject.name = "Bill";

// retrieving the value of an object via an named index using array access notation
private var firstName:String = myObject["first name"];

// setting the value of an object property using array access notation
myObject["first name""Bill";
Arrays are dynamic and, therefore, can be resized simply by adding or removing elements.

// adds an element to the end of an array and increases the array length by one
myArray.push("Phil");

// removes the last element from an array and decreases the array length by one
myArray.pop();
ActionScript supports two methods for creating Arrays, each with a variety of syntaxes:

Method #1 – Create an Array by defining (or not defining) the number of elements

// creates an array with zero elements (this is the default when no argument is passed 
to the Array constructor)
private var myArray:Array = new Array();

// creates an array with 10 elements
private var myArray:Array = new Array(10);

// creates an array with zero elements using literal notation
private var myArray:Array = [];
Method #2 – Create an array by defining the array elements and their values

private var myArray:Array = new Array("red",2);
private var myArray:Array = ["red",2];
Note: The Array class can support both initialization techniques by providing two class constructors. The appropriate constructor is used based on the argument value(s) (or lack thereof).

Arrays can also be built using MXML:

<mx:Array id="myArray"/> <!--creates an array with zero elements-->

<mx:Array id="myArray"> <!--creates an array with three elements-->
   <mx:String>myString</mx:String> <!--string-->
   <mx:Number>98</mx:Number> <!--floating-point number-->
   <mx:Object name="Phil" age="27"/> <!--object-->
</mx:Array>
Like everything in Flex, an Array is an object and as such it contains a handful of useful properties and methods.

One property familiar to all developers is the length property. The length property represents the number of array elements.

private var myArray:Array = new Array(10);
private var numberOfArrayElements:uint = myArray.length; // 10
Note: Although each Array element contains an undefined value in this scenario, the length is still 10.

The length property can be very handy. One popular technique involves using the length property to dictate the number of loops included in a For Loop.

for (var i:uint; i < myArray.length; i++) {
   trace(myArray[i]);
}
Note: You can truncate an Array by setting the length property to a value less than the number of array elements. This is not true of an ArrayCollection as the length property is read-only.

By utilizing the methods of the Array class, you can perform a number of operations on the Array elements or the Array itself. Popular Array methods include:

* filter
* indexOf
* join
* push
* reverse
* slice
* sort
* toString

However, despite all of an Array's powerful features, the inability to support data binding is a significant shortcoming. Fortunately, Flex provides an ArrayCollection.

ArrayCollection

Per the Flex Language Reference, an ArrayCollection 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".

Two members of the ArrayCollection class are integral to the ArrayCollection's ability to support data binding - The collectionChange event and addEventListener method. To participate in data binding, an object must be able to:

1. dispatch an event when something changes
2. allow other objects to listen and respond to events

The ArrayCollection satisfies both thanks to the collectionChange event and the addEventListener method and will support data binding when given a compiler directive to do so using the [Bindable] metadata tag.

// creates a bindable ArrayCollection with zero elements
[Bindableprivate var myArrayCollection:ArrayCollection = new ArrayCollection();
An ArrayCollection can be created in one of three ways:

// creating ArrayCollection with zero elements
private var myArrayCollection:ArrayCollection = new ArrayCollection();

// passing an existing Array into an ArrayCollection via the constructor
private var myArrayCollection:ArrayCollection = new ArrayCollection(myArray);

// assigning an existing Array to the source property of an ArrayCollection
private var myArrayCollection:ArrayCollection = new ArrayCollection();
myArrayCollection.source = myArray;
Either method successfully wraps an Array inside an ArrayCollection and as such, extends the capabilities of an Array.

Note: In Flex, ActionScript classes can have optional constructor parameters only. MXML does not enforce required constructor parameters, therefore, if a constructor parameter is required to create a new instance of a class, provide a default value. In the case of an ArrayCollection, the default argument for the source parameter is NULL, hence, an empty ArrayCollection is created when the source parameter is omitted.

Extending the ListCollectionView class that implements the ICollectionView and IList interfaces, an ArrayCollection inherits a handful of properties, methods and events. Therefore, your plain old Array now has a new set of functionality.

New properties include (but not limited to):

* filterFunction
* length
* list
* sort
* source

New methods include (but not limited to):

* addEventListener
* addItem
* addItemAt
* contains
* getItemAt
* getItemIndex
* refresh
* removeAll
* removeItemAt
* setItemAt

Once an Array is wrapped inside an ArrayCollection, the properties and methods of the Array class are no longer accessible unless you access them through the Array object directly. For example, if you really want to use the Array's push method, you could do the following:

myArrayCollection.source.push("new element");
This would require using the ArrayCollection's refresh method to trigger data binding.

myArrayCollection.source.push("new element");
myArrayCollection.refresh();
However, you could always use the ArrayCollection's addItem method instead.

myArrayCollection.addItem("new element");
Realize that every ArrayCollection contains an Array as the data source. If you create an empty ArrayCollection and add elements using the methods of the ArrayCollection rather than assigning an Array to the source property of an ArrayCollection, an Array is created for you.

Any data manipulation performed on an ArrayCollection will be reflected in the underlying Array and vice-versa, however, it is important to note that manipulating an Array directly will not be reflected inside an ArrayCollection until you perform a refresh of the ArrayCollection using the ArrayCollection's refresh method.

Using an ArrayCollection in place of or in tandem with an existing Array provides Flex developers with a valuable and responsive data storage and retrieval mechanism.

18 comments:

Anonymous said...

Thanks! That totally answered everything I had been wanting to know for the last hour.

Anonymous said...

Nice overview

Anonymous said...

nice overview

Alexis Hope said...

Great Thanks

Anonymous said...

nicely done...

Anonymous said...

Good!!! Thank you!!!

Anonymous said...

Its nice - how to access / update individual array elements in arraycollection?

Jeremy Mitchell said...

Access ArrayCollection elements with an arraycollection's getItemAt() method and update ArrayCollection elements with an arraycollection's setItemAt() method.

haluk said...

Thorough and clear. Thanks.

Sireesha said...

Simply Superb!! short and sweet.

Janani said...

The post is really informative.. But if you could explain the significance of Array and Array collections with a sample program, it will be more useful.. Keep up the good work!!!!

Anonymous said...

This cleared SO much up for me, even after reading all the Adobe documentation. THANK YOU, THANK YOU, THANK YOU!

Jason said...

Great post. Took me awhile to put it together, so posting this in the hopes that it might save some folks time. I needed to create a form whose multiple submissions were stored in an arrayCollection for display within a datagrid (adding mutliple contact addresses). The trick is to place the form values into an object, then add that object to the arrayCollection:
private function funcSaveContact():void {
var tempObj:Object = new Object();
tempObj.contactName = inputContactName.text;
tempObj.contactPhone = inputContactPhone.text;
arrayContacts.addItem(tempObj);

}

The datagrid uses the arrayContacts as its data provider with column values contactName and contactPhone.

aslam sayyed said...

source property can be used as the source for data binding. When this property is modified, it dispatches the listChanged event. as given in documentation

Lior said...

Great explanations!!!

Rajib Datta said...

Excellent

Anonymous said...

Superb!!

PrincessDreamWorld said...

Hey Thanks a lot :) Now no need to go anywhere to find information...
You saved my brain from getting confused and also my time and energy.