About collections and data provider components

Data provider components require data for display or user interaction. To provide this data, you assign a collection, which is usually an ArrayCollection, ArrayList, or XMLListCollection object, to the data provider component’s dataProvider property.

Optionally, for MX controls only, you can assign a raw data object such as an Array, XML, or XMLList object to the data provider component’s dataProvider property; however, this is not considered a best practice because of the limitations noted in About data provider components.

The source of data in a collection object can be local or a remote source, such as a web service or a PHP page that you call with a Flex data access component.

About collections

Collections are objects that provide a uniform way to access and represent the data contained in a data source object, such as an Array or an XMLList object. Collections provide a level of abstraction between components and the data objects that you use to populate them.

The standard collection types in the Flex framework, the ArrayCollection and XMLListCollection classes, extend the mx.collections.ListCollectionView class, which implements the mx.collections.ICollectionView and mx.collections.IList interfaces. These interfaces provide the underlying functionality for viewing and modifying data objects. An ArrayCollection object takes an Array as its source object. An XMLListCollection object take an XMLList object as its source object.

Collections provide the following features:

  • Ensure that a component is properly updated when the underlying data changes. Components are not updated when noncollection data objects change. (They are updated to reflect the new data the next time they are refreshed.) If the data provider is a collection, the components are updated immediately after the collection change occurs.

  • Provide mechanisms for handling paged data from remote data sources that may not initially be available and may arrive over a period of time.

  • Provide a consistent set of operations on the data, independent of those provided by the raw data source. For example, you can insert and delete objects by using an index into the collection, independently of whether the underlying data is, for example, in an Array or an Object.

  • Provide a specific view of the data that can be in sorted order, or filtered by a developer-supplied method. This is only a view of the data; it does not change the data.

  • Use a single collection to populate multiple components from the same data source.

  • Use collections to switch data sources for a component at run time, and to modify the content of the data source so that changes are reflected by all components that use the data source.

  • Use collection methods to access data in the underlying data source.

Note: If you use a raw data object, such as an Array, as the value of an MX control’s data provider, Flex automatically wraps the object in a collection wrapper (either an ArrayCollection or XMLListCollection). The control does not automatically detect changes that are made directly to the raw object. A change in the length of an array, for example, does not result in an update of the control. You can, however, use an object proxy, a listener interface, or the itemUpdated() method to notify the view of certain changes. For Spark controls, you cannot use a raw object as the value of the control’s data provider. You must specify an object that implements the IList interface. Classes that implement IList include ArrayCollection, ArrayList, and XMLListCollection.

Another type of collection, ArrayList, extends the IList interface but not the ICollectionView interface. As a result, it is more lightweight and provides most of the same functionality as the ArrayCollection class. It does not, however, support sorting, filtering, or cursors.

Collection interfaces

Collections use the following interfaces to define how a collection represents data and provides access to it. The standard Flex framework collections, the ArrayCollection and XMLListCollection classes, implement both the ICollectionView interface and the IList interface. The IList and ICollectionView interfaces provide alternate methods for accessing and changing data. The IList interface is simpler; it provides add, set, get, and remove operations that operate directly on linear data.

Interface

Description

IList

A direct representation of items organized in an ordinal fashion. The interface presents the data from the source object in the same order as it exists in that object, and provides access and manipulation methods based on an index. The IList class does not provide sorting, filtering, or cursor functionality.

ICollectionView

A view of a collection of items. You can modify the view to show the data in sorted order and to show a subset of the items in the source object, as specified by a filter function. A class that implements this interface can use an IList interface as the underlying collection.

The interface provides access to an IViewCursor object for access to the items.

IViewCursor

Enumerates an object that implements the ICollectionView interface bidirectionally. The view cursor provides find, seek, and bookmarking capabilities, and lets you modify the underlying data (and the view) by inserting and removing items.

The ICollectionView interface (also called the collection view) provides a more complex set of operations than the IList interface, and is appropriate when the underlying data is not organized linearly. Its data access techniques, however, are more complex than those of the IList interface, so you should use the IList interface if you need only simple, indexed access to a linear collection. The collection view can represent a subset of the underlying data, as determined by a sort or filter operation.

Collection classes

The following table describes the public classes in the mx.collections.* and spark.collections.* packages. It does not include constant, event, and error classes. For complete reference information on collection-related classes, see the MX collections, Spark collections, and collections.errors packages, and the CollectionEvent and CollectionEventKind classes in the ActionScript 3.0 Reference for the Adobe Flash Platform.

Class

Description

ArrayCollection

A standard collection for working with Arrays. Implements the IList and ICollectionView interfaces.

ArrayList

A standard collection for working with Arrays. Implements the IList interface. You can use this class instead of the ArrayCollection class if you do not need to sort, filter, or use cursors in your collection.

AsyncListView

A standard collections that handles ItemPendingErrors thrown by the getItemAt(), removeItemAt(), and toArray() methods.Use this class to support data paging when accessing data from a remote server.

XMLListCollection

A standard collection for working with XMLList objects. Implements the IList and ICollectionView interfaces, and a subset of XMLList methods.

CursorBookmark

Represents the position of a view cursor within a collection.

You can save a view cursor position in a CursorBookmark object and use the object to return the view cursor to the position at a later time.

Sort

Provides the information and methods required to sort a collection.

SortField

Provides properties and methods that determine how a specific field affects data sorting in a collection.

ItemResponder

(Used only if the data source is remote.) Handles cases when requested data is not yet available.

ListCollectionView

Superclass of the ArrayCollection and XMLListCollection classes. Adapts an object that implements the IList interface to the ICollectionView interface so that it can be passed to anything that expects an IList or an ICollectionView.

About data provider components

Several Flex components, including all list-based controls, are called data provider components because they have a dataProvider property that consumes data from an ArrayCollection, ArrayList, XMLListCollection object, or a custom collection. For example, the value of an MX Tree control’s dataProvider property determines the structure of the tree and any associated data assigned to each tree node, and a ComboBox control’s dataProvider property determines the items in the control’s drop-down list. Many standard controls, including the ColorPicker and MenuBar controls, also have a dataProvider property.

For Spark list-based controls, the value of the dataProvider property must implement the IList interface. Classes that implement IList include ArrayCollection, ArrayList, and XMLListCollection.

For the MX list-based controls, you can specify raw data objects, such as an Array of strings or objects or an XML object, the value of the dataProvider property. For MX controls, Flex automatically wraps the raw data in a collection.

Adobe recommends that you always specify a collection as the value of the dataProvider property. Using collections explicitly ensures data synchronization and provides both simpler and more sophisticated data access and manipulation tools than are available when you are using raw objects directly as data providers. Collections can also provide a consistent interface for accessing and managing data of different types. For more information about collections, see About collections and data provider components.

Although raw data objects for MX controls are automatically wrapped in an ArrayCollection object or XMLListCollection, they are subject to the following limitations:

  • Raw objects are often not sufficient if you have data that changes, because the data provider component does not receive a notification of any changes to the base object. The component therefore does not get updated until it must be redrawn due to other changes in the application, or if the data provider is reassigned. At that time, it gets the data again from the updated raw object.

  • Raw objects do not provide advanced tools for accessing, sorting, or filtering data. For example, if you use an Array as the data provider, you must use the native Adobe® Flash® Array methods to manipulate the data.

For detailed descriptions of the individual controls, see the pages for the controls in the ActionScript 3.0 Reference for the Adobe Flash Platform. For information on programming with many of the data provider components, see MX data-driven controls.

Data objects

The Flex framework supports the following types of data objects for populating data provider components:

Linear or list-based data objects
are flat data structures consisting of some number of objects, each of which has the same structure; they are often one-dimensional Arrays or ActionScript object graphs, or simple XML structures. You can specify one of these data structures in an ArrayList, ArrayCollection or XMLListCollection object’s source property or as the value of a data provider control’s dataProvider property.

You can use list-based data objects with all data provider controls, but you do not typically use them with Tree and most menu-based controls, which typically use hierarchical data structures. For data that can change dynamically, you typically use an ArrayCollection, ArrayList, or XMLListCollection object to represent and manipulate these data objects rather than the raw data object. You can also use a custom object that implements the ICollectionView and/or IList interfaces. If you do not require sorting, cursors, and filtering, you can use a class that implements just the IList interface

Hierarchical data objects
consist of cascading levels of often asymmetrical data. Often, the source of the data is an XML object, but the source can be a generic Object tree or trees of typed objects. You typically use hierarchical data objects with Flex controls that are designed to display hierarchical data:
  • Tree

  • Menu

  • MenuBar

  • PopUpMenuButton

A hierarchical data object matches the layout of a tree or cascading menu. For example, a tree often has a root node, with one or more branch or leaf child nodes. Each branch node can hold additional child branch or leaf nodes, but a leaf node is an endpoint of the tree.

The Flex hierarchical data provider controls use data descriptor interfaces to access and manipulate hierarchical data objects, and the Flex framework provides one class, the DefaultDataDescriptor class, which implements the required interfaces. If your data object does not conform to the structural requirements of the default data descriptor, you can create your own data descriptor class that implements the required interfaces.

You can use an ArrayCollection object or XMLListCollection object, or a custom object that implements the ICollectionView and IList interfaces to access and manipulate dynamic hierarchical data.

You can also use a hierarchical data object with controls that take linear data, such as the List control and the DataGrid control, by extracting specific data for linear display.

For more information on using hierarchical data providers, see Hierarchical data objects.

Specifying data providers in MXML applications

The Flex framework lets you specify and access data for data provider components in many ways. For example, you can bind a collection that contains data from a remote source to the dataProvider property of a data provider component; you can define the data provider in a dataProvider child tag of a data provider component; or you can define the data provider in ActionScript.

All access techniques belong to one of the following patterns, whether data is local or is provided from a remote source:

  • Using a collection implementation, such as an ArrayList object, ArrayCollection object, or XMLListCollection object, directly. This pattern is particularly useful for collections where object reusability is not important.

  • Using a collection interface. This pattern provides the maximum of independence from the underlying collection implementation.

  • Using a raw data object, such as an Array, with an MX list-based control. This pattern is discouraged unless data is completely static.

Using a collection object explicitly

You can use a collection, such as an ArrayList, ArrayCollection, or XMLListCollection object, as a data provider explicitly in an MXML control by assigning it to the component’s dataProvider property. This technique is more direct than using an interface and is appropriate if the data provider is always of the same collection type.

For list-based controls, you often use an ArrayList object as the data provider, and populate the ArrayList object by using an Array that is local or from a remote data source. The following example shows an ArrayList object declared in line in a ComboBox control:

<?xml version="1.0"?>
<!-- dpcontrols\ArrayCollectionInComboBox.mxml -->
<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">
    
    <s:ComboBox id="myCB"> 
        <s:ArrayList id="stateArray">
            <fx:Object label="AL" data="Montgomery"/>
            <fx:Object label="AK" data="Juneau"/>
            <fx:Object label="AR" data="Little Rock"/>
        </s:ArrayList>
    </s:ComboBox>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, the default property of the ComboBox control, dataProvider, defines an ArrayList object. Because dataProvider is the default property of the ComboBox control, it is not declared. The default property of the ArrayList object, source, is an Array of Objects, each of which has a label and a data field. Because the ArrayList object’s source property takes an Array object, it is not necessary to declare the <fx:Array> tag as the parent of the <fx:Object> tags.

The following example uses ActionScript to declare and create an ArrayList object:

<?xml version="1.0"?>
<!-- dpcontrols\ArrayCollectionInAS.mxml -->
<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="initData();">
    
    <fx:Script>
        <![CDATA[
            import mx.collections.*;
            [Bindable]
            public var stateArray:ArrayList;
            
            public function initData():void {
                stateArray=new ArrayList(
                [{label:"AL", data:"Montgomery"},
                {label:"AK", data:"Juneau"},
                {label:"AR", data:"Little Rock"}]);
            }
        ]]>
    </fx:Script>

    <s:ComboBox id="myComboBox" dataProvider="{stateArray}"/>
</s:Application>

The executing SWF file for the previous example is shown below:

After you define the ComboBox control, the dataProvider property of the ComboBox control provides access to the collection that represents the underlying source object, and you can use the property to modify the data provider. If you add the following button to the preceding code, for example, you can click the button to add the label and data for Arizona to the end of the list in the ComboBox control, as in the following example:

<s:Button label="Add AZ" 
    click="stateArray.addItem({'label':'AZ', 'data':'Phoenix'});"/>

In many cases, an ArrayList class is adequate for defining a non-XML data provider. However, for web services, remote objects, and uses that require cursors, filters, and sorts, you use the ArrayCollection class.

The following example shows an ArrayCollection object that is populated from a remote data source, in this case a remote object, as the data provider of a DataGrid control. Note that the ArrayUtil.toArray() method is used to ensure that the data sent to the ArrayCollection object is an Array.
<?xml version="1.0"?>
<!-- dpcontrols\ROParamBind22.mxml --> 
<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">
    <s:layout>
        <s:VerticalLayout gap="10"/>
    </s:layout>
    
    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.utils.ArrayUtil;
        ]]>
    </fx:Script>
    
    <fx:Declarations>
        <mx:RemoteObject
            id="employeeRO"
            destination="roDest"
            showBusyCursor="true"
            fault="Alert.show(event.fault.faultString, 'Error');">
            <mx:method name="getList">
                <mx:arguments>
                    <deptId>{dept.selectedItem.data}</deptId>
                </mx:arguments>
            </mx:method>
        </mx:RemoteObject>

        <mx:ArrayCollection id="employeeAC" 
            source="{ArrayUtil.toArray(employeeRO.getList.lastResult)}"/>
    </fx:Declarations>

    <s:HGroup>
        <s:Label text="Select a department:"/>
        <s:ComboBox id="dept" width="150">
            <s:dataProvider>
                <mx:ArrayCollection>
                    <mx:source>
                        <fx:Object label="Engineering" data="ENG"/>
                        <fx:Object label="Product Management" data="PM"/>
                        <fx:Object label="Marketing" data="MKT"/>
                    </mx:source>
                </mx:ArrayCollection>
            </s:dataProvider>
        </s:ComboBox>
        <s:Button label="Get Employee List"
            click="employeeRO.getList.send()"/>
    </s:HGroup>
    
    <mx:DataGrid dataProvider="{employeeAC}" width="100%">
        <mx:columns>
            <mx:DataGridColumn dataField="name" headerText="Name"/>
            <mx:DataGridColumn dataField="phone" headerText="Phone"/>
            <mx:DataGridColumn dataField="email" headerText="Email"/>
        </mx:columns>
    </mx:DataGrid>
</s:Application>

Accessing data by using collection interfaces

If you know that a control’s data can always be represented by a specific collection class, use an ArrayList, ArrayCollection, or XMLListCollection object explicitly, as shown above. If your code might be used with different types of collections—for example, if you might switch between object-based data and XML data from a remote data service—then you should use the ICollectionView interface in your application code, as the following example shows:

public var myICV:ICollectionView = indeterminateCollection; 
... 
<s:ComboBox id="cb1" dataProvider="{myICV}" initialize="sortICV()"/> 

You can then manipulate the interface as needed to select data for viewing, or to get and modify the data in the underlying data object.

Using a raw data object as a data provider for an MX control

When the data is static, you can use a raw data object, such as an Array object, directly as a data provider for an MX control. For example, you could use an array for a static list of U.S. Postal Service state designators. Do not use the data object directly as the dataProvider property of a control if the object contents can change dynamically, for example in response to user input or programmatic processing.
Note: For Spark list-based controls, you cannot use a raw object as the value of the control’s data provider. You must specify an object that implements the IList interface. Classes that implement IList include ArrayCollection, ArrayList, and XMLListCollection.

The result returned by an HTTP service or web service is often an Array, and if you treat that data as read-only, you can use the Array directly as a data provider. However, it is a better practice to use a collection explicitly. List-based controls turn Array-based data providers into collections internally, so there is no performance advantage to using an Array directly as the data provider. If you pass an Array to multiple controls, it is more efficient to convert the Array into a collection when the data is received, and then pass the collection to the controls.

The following example shows an MX ComboBox control that takes a static Array as its dataProvider value. As noted previously, using raw objects as data providers is not a best practice and should be considered only for data objects that will not change.

<?xml version="1.0"?>
<!-- dpcontrols/StaticComboBox.mxml -->
<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:Script>
        <![CDATA[
            [Bindable]
            public var myArray:Array = ["AL", "AK", "AR"]; 
        ]]>
    </fx:Script>
    
    <mx:ComboBox id="myCB0" dataProvider="{myArray}"/> 
</s:Application>

The executing SWF file for the previous example is shown below:

In the preceding example, the Array specified as the dataProvider is automatically wrapped in an ArrayCollection object. This is the default type for data providers to be wrapped in. If the data provider were an XML or XMLList object, it would be wrapped in an XMLListCollection object. In this example, the ArrayCollection does not have an id property, but you can use ArrayCollection methods and properties directly through the dataProvider property, as the following example shows:

<mx:Button label="Add AZ"      
    click="myCB0.dataProvider.addItem({'label':'AZ','data':'Phoenix'});"/>

Setting a data provider in ActionScript

You may set the dataProvider property of a control in ActionScript, as well as in MXML, as the following example shows:

<?xml version="1.0"?>
<!-- dpcontrols/DataGridValidateNow.mxml -->
<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="initData();">

   <fx:Script>
       <![CDATA[
    
            import mx.collections.ArrayList;

            [Bindable]
            private var DGArray:ArrayList = new ArrayList([
                {Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
                {Artist:'Pavement', Album:'Brighten the Corners', Price:11.99}]);
         
            // Initialize initDG ArrayList variable from the ArrayList.
            public function initData():void {
                myGrid.dataProvider = DGArray;
            }
        ]]>
   </fx:Script>

   <mx:DataGrid id="myGrid">
      <mx:columns>
         <mx:DataGridColumn dataField="Album"/>
         <mx:DataGridColumn dataField="Price"/>
      </mx:columns> 
   </mx:DataGrid>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, you use the intialize event to set the dataProvider property of the DataGrid control.

In some situations, you might set the dataProvider property, and then immediately attempt to perform an action on the control based on the setting of the dataProvider property, as the following example shows:

<?xml version="1.0"?>
<!-- dpcontrols/DataGridValidateNowSelindex.mxml -->
<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="initData();">

   <fx:Script>
       <![CDATA[
            import mx.collections.ArrayList;

            [Bindable]
            private var DGArray:ArrayList = new ArrayList([
                {Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
                {Artist:'Pavement', Album:'Brighten the Corners', Price:11.99}]);
         
            // Initialize initDG ArrayList variable from the ArrayList.
            public function initData():void {
                myGrid.dataProvider = DGArray;
                myGrid.validateNow();
                myGrid.selectedIndex=1;
            }
        ]]>
   </fx:Script>

   <mx:DataGrid id="myGrid">
      <mx:columns>
         <mx:DataGridColumn dataField="Album"/>
         <mx:DataGridColumn dataField="Price"/>
      </mx:columns> 
   </mx:DataGrid>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, setting the selectedindex to 1 might fail because the DataGrid control is in the process of setting the dataProvider property. Therefore, you insert the validateNow() method after setting the data provider. The validateNow() method validates and updates the properties and layout of the control, and then redraws it, if necessary.

Do not insert the validateNow() method every time you set the dataProvider property because it can affect the performance of your application; it is only required in some situations when you attempt to perform an operation on the control immediately after setting its dataProvider property.

Example: Using a collection

The following sample code shows how you can use a standard collection, an ArrayCollection object, to represent and manipulate an Array for use in a control. This example shows the following features:

  • Using an ArrayCollection to represent data in an Array

  • Sorting the ArrayCollection

  • Inserting data in the ArrayCollection

Note that if the example did not include sorting, it could use an ArrayList rather than an ArrayCollection as the data provider.

This example also shows the insertion’s effect on the Array and the ArrayCollection representation of the Array:

<?xml version="1.0"?>
<!-- dpcontrols\SimpleDP.mxml -->
<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" width="600" 
    initialize="sortAC();">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import spark.collections.Sort;
            import spark.collections.SortField;
    
            // Function to sort the ArrayCollection in descending order.
            public function sortAC():void {
                var sortA:Sort = new Sort();
                sortA.fields=[new SortField("label")];
                myAC.sort=sortA;
                //Refresh the collection view to show the sort.
                myAC.refresh();
            }
            // Function to add an item in the ArrayCollection.
            // Data added to the view is also added to the underlying Array.
            // The ArrayCollection must be sorted for this to work.
            public function addItemToMyAC():void {
                myAC.addItem({label:"MD", data:"Annapolis"});
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- An ArrayCollection with an array of objects -->
        <mx:ArrayCollection id="myAC">
            <!-- Use an fx:Array tag to associate an id with the array. --> 
            <fx:Array id="myArray">
                <fx:Object label="MI" data="Lansing"/>
                <fx:Object label="MO" data="Jefferson City"/>
                <fx:Object label="MA" data="Boston"/>
                <fx:Object label="MT" data="Helena"/>
                <fx:Object label="ME" data="Augusta"/>
                <fx:Object label="MS" data="Jackson"/>
                <fx:Object label="MN" data="Saint Paul"/>
            </fx:Array> 
        </mx:ArrayCollection>
    </fx:Declarations>

    <s:HGroup width="100%">
        <!-- A ComboBox populated by the collection view of the Array. -->
        <s:ComboBox id="cb1" dataProvider="{myAC}"/>
        <s:Button id="b1" label="Add MD" click="addItemToMyAC();"/>
    </s:HGroup>
</s:Application>

The executing SWF file for the previous example is shown below: