Tuesday, October 30, 2007

Using addItemAt(Object, int) With ArrayCollection

The Flex ArrayCollection is a handy mechanism for working with Arrays. Its ListCollectionView heritage provides highly useful array manipulation methods such as addItemAt(), setItemAt(), removeItemAt(), and removeAll(). However, there are a few minor issues to be aware of when using ArrayCollection. This blog entry covers one of these -- the need to ensure that the addItemAt() method adds an item at the appropriate location within the ArrayCollection.

If you instantiate an ArrayCollection with an empty constructor, it is important to make an initial addItemAt(Object,int) call on index 0 rather than index 1 or any higher number. If an attempt is made to call ArrayCollection.addItemAt(Object,int) for an index which is greater than the list size, a RangeError is thrown. So, for a newly instantiated ArrayCollection based on an empty array, the only allowable index to call addItemAt(Object,int) is zero [addItemAt(someObject,0)]. Note that this is equivalent to calling ArrayCollection.addItem(Object) with the empty underlying array.

The following ActionScript code snippet illustrates this.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="750" height="500"

import mx.controls.Alert;
import mx.collections.ArrayCollection;

* To compile solely this Flex application from the command line, use
* mxmlc -compiler.debug=true ArrayCollectionExample.mxml
* This application demonstrates how a RangeError can occur if addItemAt()
* is used at an array index past the end of the Array.

[Bindable] private var example1Array:ArrayCollection =
new ArrayCollection();
[Bindable] private var example2Array:ArrayCollection =
new ArrayCollection();

public function handleArrayCollection():void
var index1:int = 0;
for ( index1 ; index1 < 5 ; index1++ )
example1Array.addItemAt("item one", index1);
Alert.show( "example1Array has " + example1Array.length
+ " items!");

var index2:int = 1;
for ( index2 ; index2 < 5; index2++ )
example2Array.addItemAt("item two", index2);
Alert.show( "example2Array has " + example2Array.length
+ " items!");


The above code listing compiles fine, but example2Array has issues at runtime because the for loop that inserts values into it using addItemAt() starts trying to add at index 1 rather than index 0 for this newly allocated ArrayCollection. This results in an error stating: "RangeError: Index '1' specified is out of bounds." Note that the first array, array1example, runs fine because addItemAt() starts by adding at its zero index rather than its one index.

The error message that will be encountered when ActionScript code attempts to addItemAt(1) without ever first creating an item at index 0 is shown here:

RangeError: Index '1' specified is out of bounds.
at mx.collections::ListCollectionView/addItemAt()[C:\dev\flex_201_gmc\sdk\frameworks\mx\collections\ListCollectionView.as:531]
at ArrayCollectionExample/handleArrayCollection()[C:\flexExamples\ArrayCollectionRange\ArrayCollectionExample.mxml:34]
at ArrayCollectionExample/___Application1_applicationComplete()[C:\flexExamples\ArrayCollectionRange\ArrayCollectionExample.mxml:3]

The error contains a longer trace than that shown above, but the important lines are displayed above. The next screen snapshot shows how the error message looks in the debugger:

One other interesting observation can be had here by renaming the source code shown above from a file named ArrayCollectionExample.mxml to ArrayCollection.mxml. Now, with a local application file with the same name as a type used in the application, we see the following types of compiler error messages:

  • "Error: Call to a possibly undefined method addItemAt through a reference with static type ArrayCollection."

  • "Error: Access of possibly undefined property length through a reference with static type ArrayCollection."

The above compiler error messages occur because of the attempt of the code to act upon instances of ArrayCollection and the file with the source code is itself called ArrayCollection. Renaming the file to something like ArrayCollectionExample.mxml fixes the compiler errors.

For additional information on Flex's ArrayCollection, see Flex, Array, ArrayCollection (which talks about using ArrayCollection rather than Array for data binding) and Dave Carabetta's Array Versus ArrayCollection in Flex 2 (brief explanation of difference between Array and ArrayCollection).

No comments: