Adobe Flex 3 Help

Working with data views

Collections provide a view of the underlying data object as a collection of items. This functionality is defined in the ICollectionView interface. Although they are more complex, data views give you more flexibility than the simple data access methods and properties that are defined in the IList interface. Data views provide the following features:

  • You can modify the data view to show the data in sorted order or to show a subset of the items in the data provider without changing the underlying data. For more information, see Sorting and filtering data for viewing.
  • You can access the collection data by using a cursor, which lets you move through the collection, use bookmarks to save specific locations in the collection, and insert and delete items in the collection (and therefore in the underlying data source). For more information, see Using a view cursor.
  • You can represent remote data that might not initially be available, or parts of the data set that might become available at different times. For more information, see Collection change notification and Remote data in data provider components.

You can use data views directly on ArrayCollection and XMLListCollection objects and also on the dataProvider property of standard Flex data provider components except those that are subclasses of the NavBar class (ButtonBar, LinkBar, TabBar, and ToggleButtonBar). It is a better practice to work directly on the collection objects than on the dataProvider property.

Sorting and filtering data for viewing

Collections let you sort and filter data in the data view so that the data in the collection is a reordered subset of the underlying data. Data view operations have no effect on the underlying data object content, only on the subset of data that the collection view represents, and therefore on what is displayed by any control that uses the collection.

Sorting

A Sort object lets you sort data in a collection. You can specify multiple fields to use in sorting the data, require that the resulting entries be unique, and specify a custom comparison function to use for ordering the sorted output. You can also use a Sort object to find items in a collection. When you create a Sort object, or change its properties, you must call the refresh() method on the collection to show the results.

You use SortField objects to specify the fields to use in the sort. You create SortField objects and put them in the Sort class object's fields array.

The following example shows a function to sort a collection. In this example, myAC is an ArrayCollection that contains an Array with label and name fields. The primary sort is a descending, case-insensitive sort on the area field, and the secondary sort is an ascending, case-sensitive sort on the label field. You might call it as the initialize event handler for a control that must display a specific sorted view of a collection.

//Sort the collection in descending order.
public function sortAC():void {
    //Create a Sort object.
    var sortA:Sort = new Sort();
    // Sort first on the area field, then the label field.
    // The second parameter specifies that the sort is case-insensitive.
    // A true third parameter specifies a descending sort.
    sortA.fields=[new SortField("area", true, true), 
                        new SortField("label")];
    myAC.sort=sortA;
    //Refresh the collection to show the sort.
    myAC.refresh();
}

Filtering

You use a filter function to limit the data view in the collection to a subset of the source data object. The function must take a single Object parameter, which corresponds to a collection item, and must return a Boolean value specifying whether to include the item in the view. As with sorting, when you specify or change the filter function, you must call the refresh() method on the collection to show the filtered results. To limit a collection view of an array of strings to contain only strings starting with M, for example, use the following filter function:

public function stateFilterFunc(item:Object):Boolean
{
    return item >= "M" && item < "N";
}

Example: Sorting and filtering an ArrayCollection

The following example shows the use of the filter function and a sort together. You can use the buttons to sort the collection, to filter the collection, or to do both. Use the Reset button to restore the collection view to its original state.

<?xml version="1.0"?>
<!-- dpcontrols\SortFilterArrayCollection.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600">
    <mx:Script>
        <![CDATA[
            import mx.collections.*;
    
            /* Function to sort the ICollectionView
               in ascending 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 filter out all items with labels
               that are not in the range of M-N. */
            public function stateFilterFunc(item:Object):Boolean {
                return item.label >= "M" && item.label < "O";
            }
            
            /* Function to apply the filter function the ICollectionView. */
            public function filterAC():void {
                myAC.filterFunction=stateFilterFunc;
                /* Refresh the collection view to apply the filter. */
                myAC.refresh();
            }

            /* Function to Reset the view to its original state. */
            public function resetAC():void {
                myAC.filterFunction=null;
                myAC.sort=null;
                //Refresh the collection view.
                myAC.refresh();
            }

        ]]>
    </mx:Script>

    <!-- An ArrayCollection with an array of objects. -->
    <mx:ArrayCollection id="myAC">
        <mx:Array id="myArray">
            <mx:Object label="LA" data="Baton Rouge"/>
            <mx:Object label="NH" data="Concord"/>
            <mx:Object label="TX" data="Austin"/>
            <mx:Object label="MA" data="Boston"/>
            <mx:Object label="AZ" data="Phoenix"/>
            <mx:Object label="OR" data="Salem"/>
            <mx:Object label="FL" data="Tallahassee"/>
            <mx:Object label="MN" data="Saint Paul"/>
            <mx:Object label="NY" data="Albany"/>
        </mx:Array> 
    </mx:ArrayCollection>

    <!-- Buttons to filter, sort, or reset the view in the second ComboBox
            control. -->
    <mx:HBox width="100%">
        <mx:Button id="sortButton" label="Sort" click="sortAC();"/>
        <mx:Button id="filterButton" label="Filter" click="filterAC();"/>
        <mx:Button id="resetButton" label="Reset" click="resetAC();"/>
    </mx:HBox>
    <mx:VBox width="550" height="143" borderStyle="solid" paddingTop="10" paddingLeft="10">
        <mx:Label text="This box retains original order and contents of the Array:"/>
        <!-- A ComboBox populated by the underlying Array object.
            This control shows that Array retains its original order. -->
        <mx:ComboBox id="cb2" rowCount="10" dataProvider="{myArray}"/>
        <mx:HRule/>
        <mx:Label text="This box reflects the changes to the Array:"/>
        <!-- A ComboBox populated by the collection view of the Array. -->
        <mx:ComboBox id="cb1" rowCount="10" dataProvider="{myAC}"/>
    </mx:VBox>
</mx:Application>

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

For a more complex example of sorting a DataGrid control, which does both an initial sort of the data and a custom sort when you click a column heading, see Example: Sorting a DataGrid on multiple columns.

Using a view cursor

You use a view cursor to traverse the items in a collection's data view and to access and modify data in the collection. A cursor is a position indicator; it points to a particular item in the collection. Collections have a createCursor() method that returns a view cursor. View cursor methods and properties are defined in the IViewCursor interface.

You can use view cursor methods and properties to perform the following operations:

  • Move the cursor backward or forward
  • Move the cursor to specific items
  • Get the item at a cursor location
  • Add, remove, and change items
  • Save a cursor position by using a bookmark, and return to it later

When you use standard Flex collection classes, ArrayCollection and XMLListCollection, you use the IViewCursor interface directly; as the following code snippet shows, you do not reference an object instance:

public var myAC:ICollectionView = new ArrayCollection(myArray); 
public var myCursor:IViewCursor;
.
.
myCursor=myAC.createCursor();

Manipulating the view cursor

A view cursor object includes the following methods and properties for moving the cursor:

  1. The moveNext() and movePrevious() methods move the cursor forward and backward by one item. Use the beforeFirst and afterLast properties to check whether you've reached the bounds of the view. The following example moves the cursor to the last item in the view:
    while (! myCursor.afterLast) {
            myCursor.moveNext();
    }
    
    
  2. The findAny(), findFirst(), and findLast() methods move the cursor to an item that matches the parameter. Before you can use these methods, you must apply a Sort to the collection (because the functions use Sort methods).

If it is not important to find the first occurrence of an item or the last occurrence of an item in a nonunique index, the findAny() method can be somewhat more efficient than either the findFirst() or the findLast() method.

If the associated data is from a remote source, and not all of the items are cached locally, the find methods begin an asynchronous fetch from the remote source; if a fetch is already in progress, they wait for it to complete before making another fetch request.

The following example finds an item inside a collection of simple objects--in this case, an ArrayCollection of state ZIP code strings. It creates a default Sort object, applies it to an ArrayCollection object, and finds the first instance of the string "MZ" in a simple array of strings:

var sortD:Sort = new Sort();
// The null first parameter on the SortField constructor specifies a
// collection of simple objects (String, numeric, or Boolean values).
// The true second parameter specifies a case-insensitive sort.
sortD.fields = [new SortField(null, true)];
myAC.sort=sortD;
myAC.refresh();
myCursor.findFirst("MZ");

To find a complex object, you can use the findFirst() method to search on multiple sort fields. You cannot, however, skip fields in the parameter of any of the find methods. If an object has three fields, for example, you can specify any of the following field combinations in the parameter: 1, 1,2, or 1,2,3, but you cannot specify only fields 1 and 3.

Both of the following lines find an object with the label value "ME" and data value "Augusta":

myCursor.findFirst({label:"ME"});
myCursor.findFirst({label:"ME", data:"Augusta"});

  1. The seek() method moves the cursor to a position relative to a bookmark. You use this method to move the cursor to the first or last item in a view, or to move to a bookmark position that you have saved. For more information on using bookmarks and the seek() method, see Using bookmarks.

Getting, adding, and removing data items

A view cursor object includes the following methods and properties for accessing and changing data in the view:

  • The current property is a reference to the item at the current cursor location.
  • The insert() method inserts an item before the current cursor location. However, if the collection is sorted (for example, to do a find() operation, the sort moves the item to the sorted order location, not to the cursor location.
  • The remove() method removes the item at the current cursor location; if the removed item is not the last item, the cursor points to the location after the removed item.

The following example shows the results of using insert() and remove() on the current property:

<?xml version="1.0"?>
<!-- dpcontrols\GetAddRemoveItems.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
        initialize="initData();">
    <mx:Script>
        <![CDATA[
            import mx.collections.*;
            public var myArray:Array = [{label:"MA", data:"Massachusetts"}, 
            {label:"MN", data:"Minnesota"}, {label:"MO", data:"Missouri"}];
            [Bindable]
            public var myAC:ArrayCollection; 
            public var myCursor:IViewCursor;

            /* Initialize the ArrayCollection when you
               initialize the application. */
            public function initData():void {
                myAC = new ArrayCollection(myArray); 
            }

            /* The function to change the collection,
               and therefore the Array. */
            public function testCollection():void {
                /* Get an IViewCursor object for accessing the collection data. */
                myCursor=myAC.createCursor();
                ta1.text="At start, the cursor is at: " + myCursor.current.label + ".";
                var removedItem:String=String(myCursor.remove());
                ta1.text+="\nAfter removing the current item, the cursor is at: " 
                    + myCursor.current.label + ".";
                myCursor.insert({label:"ME", data:"Augusta"});
                ta1.text+="\nAfter adding an item, the cursor is at: " 
                    + myCursor.current.label + ".";
            }
        ]]>
    </mx:Script>

    <mx:ComboBox id="myCB" rowCount="7" dataProvider="{myAC}"/>
    <mx:TextArea id="ta1" height="75" width="350"/> 
    <mx:Button label="Run Test" click="testCollection();"/>
</mx:Application>

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

Using bookmarks

You use a bookmark to save a cursor location for later use. You can also use the built-in FIRST and LAST bookmark properties to move the cursor to the first or last item in the data view.

Create and use a bookmark

  1. Move the cursor to a desired location in the data view.
  2. Assign the current value of the bookmark property to a variable, as in the following line:
    var myBookmark:CursorBookmark=myCursor.bookmark;
    
    
  3. Do some operations that might move the cursor.
  4. When you must return to the bookmarked cursor location (or to a specific offset from the bookmarked location), call the IViewCursor seek() method, as in the following line:
    myCursor.seek(myBookmark);
    
    

The following example counts the number of items in a collection between the selected item in a ComboBox control and the end of the collection, and then returns the cursor to the initial location:

<?xml version="1.0"?>
<!-- dpcontrols\UseBookmarks.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        initialize="run();">
    <mx:Script>
        <![CDATA[
            import mx.collections.*;
            private var myCursor:IViewCursor;

            // Initialize variables.
            public function run():void {
                // Initialize the cursor.
                myCursor=myAC.createCursor();
                // The findFirst() method, used in 
                // countFromSelection() requires a
                // sorted view.
                var sort:Sort = new Sort();
                sort.fields=[new SortField("label")];
                myAC.sort=sort;
                //You must refresh the view to apply the sort.
                myAC.refresh();
            }

            // Count the items following the current
            // cursor location.
            public function countLast(theCursor:IViewCursor):int {
                var counter:int=0;
                // Set a bookmark at the current cursor location.
                var mark:CursorBookmark=theCursor.bookmark;
                // Move the cursor to the end of the Array.
                // The moveNext() method returns false when the cursor
                // is after the last item.
                    while (theCursor.moveNext()) {
                    counter++;
                }
                // Return the cursor to the initial location.
                theCursor.seek(mark);
                return counter;
            }

            // Function triggered by ComboBox change event.
            // Calls the countLast() function to count the
            // number of items to the end of the collection.
            public function countFromSelection():void {
                myCursor.findFirst(myCB.selectedItem);
                var count:int = countLast(myCursor);
                ta1.text += myCursor.current.label + " is " + count +
                                " from the last item.\n";
            }
        ]]>
    </mx:Script>

    <!-- The data provider, an ArrayCollection with an array of objects. --> 
    <mx:ArrayCollection id="myAC">
        <mx:Object label="MA" data="Boston"/>
        <mx:Object label="ME" data="Augusta"/>
        <mx:Object label="MI" data="Lansing"/>
        <mx:Object label="MN" data="Saint Paul"/>
        <mx:Object label="MO" data="Jefferson City"/>
        <mx:Object label="MS" data="Jackson"/>
        <mx:Object label="MT" data="Helena"/>
    </mx:ArrayCollection>

    <mx:ComboBox id="myCB" rowCount="7" dataProvider="{myAC}" change="countFromSelection();"/>
    <mx:TextArea id="ta1" height="200" width="175"/>
</mx:Application>

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

Example: Updating an Array by using data view methods and properties

The following example uses the data view methods and properties of an ArrayCollection object to display an Array with the following elements in a ComboBox control:

"AZ", "MA", "MZ", "MN", "MO", "MS"

When you click the Update View button, the application uses the length property and several methods of the ICollectionView interface to do the following:

  • Change the data in the array and the displayed data in the ComboBox control to a correct alphabetical list of the U.S. state abbreviations for the following states that start with the letter M:
    MA, ME, MI, MN, MO, MS, MT
    
    
  • Save a bookmark that points to the ME item that it adds, and later restores the cursor to this position.
  • Display in a TextArea control information about the tasks it performed and the resulting array.

When you click the Sort button, the application reverses the order of the items in the view, and limits the viewed range to ME-MO.

When you click the Reset button, the application resets the data provider array and the collection view.

<?xml version="1.0"?>
<!-- dpcontrols\UpdateArrayViaICollectionView.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
        initialize="initData();">
        
    <mx:Script>
        <![CDATA[
            import mx.collections.*;
            // The data provider is an array of Strings.
            public var myArray:Array = ["AZ", "MA", "MZ", "MN", "MO", "MS"];
            // Declare an ArrayCollection that represents the Array.
            // The variable must be bindable so the ComboBox can update properly.
            [Bindable]
            public var myAC:ArrayCollection;
            //Boolean flag to ensure the update routine hasn't been run before.
            public var runBefore:Boolean=false; 

            //Initialize the ArrayCollection the application initializes.
            public function initData():void {
                myAC = new ArrayCollection(myArray); 
            }

            // The function to change the collection.
            public function changeCollection():void {
                //Running this twice without resetting causes an error.
                if (! runBefore) {
                    runBefore=true; 
                    // Get an IViewCursor object for accessing the collection data.
                    var myCursor:IViewCursor=myAC.createCursor();
                    // Get the original collection length. 
                    var oldLength:int=myAC.length;

                    // The cursor is initially at the first item; delete it.
                    var removedItem:String=String(myCursor.remove());

                    // Add ME as the second item.
                    // The cursor is at the (new) first item; 
                    // move it to the second item.
                    myCursor.moveNext();
                    // Insert ME before the second item.
                    myCursor.insert("ME");

                    // Add MT at the end of the collection.
                    //Use the LAST bookmark property to go to the end of the view.
                    // Add an offset of 1 to position the cursor after the last item.
                    myCursor.seek(CursorBookmark.LAST, 1);
                    myCursor.insert("MT");
                    // Change MZ to MI.
                    // The findFirst() method requires a sorted view.
                    var sort:Sort = new Sort();
                    myAC.sort=sort;
                    // Refresh the collection view to apply the sort.
                    myAC.refresh();
                    // Make sure there is a MZ item, and no MI in the array.
                     if (myCursor.findFirst("MZ") && !myCursor.findFirst("MI")) {
                        // The IViewCursor does not have a replace operation.
                        // First, remove "MZ".
                        myCursor.remove();
                        // Because the view is now sorted, the insert puts this item 
                        // in the right place in the sorted view, but at the end of 
                        // the underlying Array data provider.
                        myCursor.insert("MI");
                    }

                    // Get the updated collection length. 
                    var newLength:int=myAC.length;

                    // Set a bookmark at the item with the value ME,
                    myCursor.findFirst("ME");
                    var MEMark:CursorBookmark=myCursor.bookmark;
                    // Move the cursor to the last item in the Array.
                    myCursor.seek(CursorBookmark.LAST);
                    // Get the last item in the collection.
                    var lastItem:String=String(myCursor.current);
                    // Return the cursor to the bookmark position.
                    myCursor.seek(MEMark);
                    // Get the item at the cursor location.
                    var MEItem:String=String(myCursor.current);

                    // Display the information in the TextArea control.
                    ta1.text="Start Length: " + oldLength + ". End Length: " 
                                    + newLength;
                    ta1.text+=".\nRemoved " + removedItem;
                    ta1.text+=".\nLast Item is " + lastItem;
                    ta1.text+=".\nItem at MEMark is " + MEItem;
                    // Show that the base Array has been changed.
                    // Notice that the Array is NOT in sorted order.
                    ta1.text+="\nThe base Array is: " + myArray.join(); 
                } // End runBefore condition
            }

            // Filter function used in the sortICV method to limit the range.
            public function MEMOFilter(item:Object):Boolean {
                return item >= "ME" && item <= "MO";
            }
            
            // Sort the collection view in descending order, 
            // and limit the items to the range ME - MO.
            public function sortICV():void {
                var sort:Sort = new Sort();
                sort.fields=[new SortField(null, false, true)];
                myAC.filterFunction=MEMOFilter;
                myAC.sort=sort;
                // Refresh the ArrayCollection to apply the sort and filter
                // function.
                myAC.refresh();
                //Call the ComboBox selectedIndex() method to replace the "MA"
                //in the display with the first item in the sorted view.
                myCB.selectedIndex=0;
                ta1.text="Sorted";
            }

            //Reset the Array and update the display to run the example again.
            public function resetView():void {
                myArray = ["AZ", "MA", "MZ", "MN", "MO", "MS"];
                myAC = new ArrayCollection(myArray);
                ta1.text="Reset";
                runBefore=false;
            }
        ]]>
    </mx:Script>

    <mx:ComboBox id="myCB" rowCount="7" dataProvider="{myAC}"/>
    <mx:TextArea id="ta1" height="75" width="300"/>
    <mx:HBox> 
        <mx:Button label="Update View" click="changeCollection();"/>
        <mx:Button label="Sort View" click="sortICV();"/> 
        <mx:Button label="Reset View" click="resetView();"/> 
    </mx:HBox>
</mx:Application>

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