by Adobe

adobe_logo_bio

Created

23 March 2010

 Requirements
 
User level
Required products
All Flex (Download trial)
Many Spark components, including all list-based controls, get their data from a data provider, an object that contains data required by the control. For example, a ComboBox control's data provider determines the items in the control's drop-down list. Controls that display application data are sometimes referred to as data provider controls.
 
This Quick Start describes the following ways of using data providers:
 

 
Using an ArrayList as a data provider

The simplest data provider is an ArrayList of Strings or Objects. The following example uses an ArrayList of Strings as a data provider to create a static ComboBox control.
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderArray.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="150" height="140"> <fx:Script> <![CDATA[ import mx.collections.*; [Bindable] public var myArray:ArrayList = new ArrayList(["AL", "AK", "AR"]); ]]> </fx:Script> <s:ComboBox id="statesCombo" dataProvider="{myArray}"/> </s:Application>
An ArrayList is like an Array, but it provides additional methods that you can use to manipulate the data. All Spark data provider controls use an ArrayList or collection class rather than an Array as a data provider. Using an ArrayList instead of an Array gives you the following benefits:
 
  • An ArrayList notifies its host component of any changes; the host component is updated immediately. Arrays do not provide any notifications of udpates.
  • An ArrayList provides some tools for accessing data. Arrays provide only very basic methods and properties.
In the following example, three bloggers' names are displayed in a List control that uses an ArrayList as its data provider. When a user presses the Add A Blogger button, Flex adds a fourth blogger's name to the ArrayList. Because the ArrayList provides notifications to its host component, the new name immediately shows up in the List control.
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderArrayAdd.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="350" height="220"> <fx:Script> <![CDATA[ import mx.collections.*; [Bindable] public var bloggersArray:ArrayList = new ArrayList( ["Andy Budd", "Grant Skinner", "Paul Booth"]); ]]> </fx:Script> <s:Panel title="Bloggers we love!" width="100%"> <s:layout> <s:VerticalLayout/> </s:layout> <s:List id="bloggersList" width="90%" dataProvider="{bloggersArray}"/> <s:Button label="Add a blogger!" click="bloggersArray.addItem('Pete-Barr Watson');"/> </s:Panel> </s:Application>

 
Using collections as data providers

Flex provides a collection mechanism to ensure data synchronization and provide both simpler and more sophisticated data access and manipulation tools. The ArrayList class is more lightweight and provides most of the same functionality as the ArrayCollection class. It does not, however, support sorting, filtering, or cursors.
 
You can use an ArrayCollection as a data provider directly in an MXML control by assigning it to the component's dataProvider property. You can do this either in MXML or by using ActionScript. If you do it in MXML, you must put the ArrayCollection definition in the <fx:Declarations> block of the application file.
 
The following example shows you how to create an ArrayCollection and apply it as the data provider of a List control by using MXML.
 
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderCollectionsMxml.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="350" height="220"> <fx:Declarations> <s:ArrayCollection id="bloggers"> <fx:Object label="Andy Budd" url="http://andybudd.com"/> <fx:Object label="Grant Skinner" url="http://gskinner.com"/> <fx:Object label="Paul Booth" url="http://paulbooth.com"/> </s:ArrayCollection> </fx:Declarations> <s:Panel title="Bloggers we love!" width="100%"> <s:layout> <s:VerticalLayout/> </s:layout> <s:Button label="Add a blogger!" click="bloggers.addItem({label:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"/> <s:List id="bloggersList" width="90%" dataProvider="{bloggers}"/> </s:Panel> </s:Application>
The following example shows you how to create an ArrayCollection and apply it as the data provider of a List control by using ActionScript.
 
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderCollectionsAS.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="350" height="220" creationComplete="creationCompleteHandler(event);"> <fx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.events.FlexEvent; private var bloggersArray:Array = [ {label: "Andy Budd", url:"http://andybudd.com"}, {label: "Grant Skinner", url:"http://gskinner.com"}, {label: "Paul Booth", url:"http://paulbooth.com"} ]; [Bindable] private var bloggersCol:ArrayCollection; private function creationCompleteHandler(event:FlexEvent):void { bloggersCol = new ArrayCollection(bloggersArray); } ]]> </fx:Script> <s:Panel title="Bloggers we love!" width="100%"> <s:layout> <s:VerticalLayout/> </s:layout> <s:Button label="Add a blogger!" click="bloggersCol.addItem({label:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"/> <s:List id="bloggersList" width="90%" dataProvider="{bloggersCol}"/> </s:Panel> </s:Application>
Tip: If you know that a control's data provider can always be represented by a specific collection class, you can use that class directly, as shown in the preceding example with the ArrayCollection class. However, if your control must be able to handle different types of collections — for example, either an ArrayCollection or an XMLListCollection — you should bind your data provider to a property of type ICollectionView as all collection classes implement the ICollectionView interface, as shown in the following snippet:
 
[Bindable] private var bloggersCol:ICollectionView;

 
Using externally loaded data as a data provider

Loading in and displaying external data is a very common feature in rich Internet applications. The HTTPService control in Flex is one mechanism for loading in external data. To display XML data read by an HTTPService control into a Flex data provider control, store the repeating set of nodes that contains your collection in an ArrayCollection and bind that to the dataProvider property of your control.
 
If you define the HTTPService in MXML, you must put the HTTPService definition in the <fx:Declarations> block of the application file.
 
Tip: Ensure that you deploy the data file to the correct location. The URL that you specify for the HTTPService control is relative to the location of the HTML file that loads in your Flex application, not relative to the location of your Flex application's SWF file.
 
Also, always use a forward slash (/) when specifying the URL for the HTTPService control. Using a backslash works when you test your Flex application offline, but may not work on your server because it may be URL encoded to %5C.
 
You can also bind your data provider control to the lastResult property of your HTTPService instance directly; however, the slightly more verbose method shown in the following example makes the code easier to maintain and scale.
 
The following example uses an HTTPService control to read in an XML file and then uses the read-in data as the data provider for a List control.
 
 
Example
Model (bloggers.xml)
 
<bloggers> <blogger> <name>Andy Budd</name> <url>http://andybudd.com</url> </blogger> <blogger> <name>Grant Skinner</name> <url>http://gskinner.com</url> </blogger> <blogger> <name>Paul Booth</name> <url>http://paulbooth.com</url> </blogger> </bloggers>
Main application file
 
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderExternal.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="350" height="220" creationComplete="bloggerService.send();"> <!-- Service to load in XML --> <fx:Declarations> <mx:HTTPService id="bloggerService" url="../assets/bloggers.xml" invoke="bsInvokeHandler(event);" result="bsResultHandler(event);" fault="bsFaultHandler(event);"/> </fx:Declarations> <fx:Script> <![CDATA[ import mx.managers.CursorManager; import adobe.utils.CustomActions; import mx.rpc.events.InvokeEvent; import mx.controls.Alert; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.collections.ArrayCollection; [Bindable] private var bloggersCol:ArrayCollection; /* Gets called when HTTPService is invoked to request the XML. */ private function bsInvokeHandler(event:InvokeEvent):void { /* Display the busy cursor. */ CursorManager.setBusyCursor(); } /* Gets called when the XML is successfully loaded. */ private function bsResultHandler(event:ResultEvent):void { /* Save a reference to the list of bloggers. */ bloggersCol = event.result.bloggers.blogger; /* Hide the busy cursor. */ CursorManager.removeBusyCursor(); } private function bsFaultHandler(event:FaultEvent):void { /* There was an error in loading the XML. */ Alert.show ( event.fault.message ); /* Hide the busy cursor. */ CursorManager.removeBusyCursor(); } ]]> </fx:Script> <s:Panel title="Bloggers we love!" width="100%"> <s:layout> <s:VerticalLayout/> </s:layout> <s:List id="bloggersList" width="90%" dataProvider="{bloggersCol}" labelField="name"/> <s:Button label="Add a blogger!" click="bloggersCol.addItem({name:'Pete-Barr Watson', url:'http://petebarrwatson.com/'});"/> </s:Panel> </s:Application>
Note: Depending on how your environment is set up, you might have to add the use-network=false compiler argument when compiling this example. This will prevent the application from being able to make remote network calls. Instead, it will be able to access a file (in this case, bloggers.xml) on the local file system.
 

 
Modifying data in data providers and listening for events

The ArrayList and collection classes in Flex implement the IList interface which provides methods for modifying (adding, removing, updating) items in a collection. You can use the IList interface methods and properties directly on any of the following classes or properties:
 
  • ArrayCollection class
  • ArrayList class
  • XMLList class
  • dataProvider property of standard Flex controls
The most important methods in the IList interface are addItem(), removeItem(), and setItemAt() for adding, removing, and updating data items, respectively. There are also addItemAt() and removeItemAt() methods, which, like the setItemAt() method, take a second parameter that corresponds to the index in the collection that you want to affect. The length property exposed by the IList interface returns the number of items in a collection.
 
The Flex collection mechanism includes events that represent changes to the collection. Classes that implement the IList or ICollectionView interface dispatch a CollectionEvent class event (mx.events.CollectionEvent) whenever the collection changes. All collection events have the type property value CollectionEvent.COLLECTION_CHANGE.
 
Note: The Collection classes also implement the ICollectionView interface. This interface adds sorting and filtering. For more information, see mx.collections.ICollectionView.
 
The CollectionEvent object includes a kind property that indicates the way in which the collection changed; you can determine the change by comparing the kind property value with the CollectionEventKind constants. The main constants are ADD, REMOVE, and UPDATE.
 
The CollectionEvent object also includes an items property that is an Array of objects whose type varies depending on the kind of event that the object dispatched. For ADD and REMOVE events, the array contains the added or removed items. For UPDATE events, the items property contains an Array of PropertyChangeEvent event objects. These objects' properties indicate the type of changes and the propertys' values before and after the changes. For example, the kind property of the PropertyChangeEvent class indicates the way in which the property changed; you can determine the change type by comparing the kind property value with the PropertyChangeEventKind constants, UPDATE and DELETE.
 
The following example listens for the change event on a DataGrid control to create a master-detail relationship in which selecting a row on the DataGrid displays the data in that row in several form controls so you can edit the data. (An alternative to using a master-detail relationship is to make the DataGrid control editable.) The example lets you add, remove, or modify data in a DataGrid control using the addItem(), removeItem(), and setItemAt() methods of the IList interface. It also listens for the collectionChange event on the ArrayCollection to keep a log of data that is added, removed and updated.
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- using_data_providers/DataProviderModifyingAndEvents.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="525" height="530"> <s:layout> <s:VerticalLayout/> </s:layout> <fx:Declarations> <!-- The ArrayCollection used by the DataGrid and ComboBox. --> <s:ArrayCollection id="ac" collectionChange="collectionEventHandler(event)"> <fx:Object first="Matt" last="Matthews" email="matt@myco.com"/> <fx:Object first="Sue" last="Sanderson" email="sue@myco.com"/> <fx:Object first="Harry" last="Harrison" email="harry@myco.com"/> </s:ArrayCollection> </fx:Declarations> <fx:Script> <![CDATA[ import mx.events.*; import mx.collections.*; /* Add event information to a log (displayed in the TextArea). */ public function collectionEventHandler(event:CollectionEvent):void { switch(event.kind) { case CollectionEventKind.ADD: addLog("Item "+ event.location + " added"); break; case CollectionEventKind.REMOVE: addLog("Item "+ event.location + " removed"); break; case CollectionEventKind.REPLACE: addLog("Item "+ event.location + " Replaced"); break; case CollectionEventKind.UPDATE: addLog("Item updated"); break; } } /* Helper function for adding information to the log. */ public function addLog(str:String):void { log.text += str + "\n"; } /* Add a person to the ArrayCollection. */ public function addPerson():void { ac.addItem({first:firstInput.text, last:lastInput.text, email:emailInput.text}); clearInputs(); } /* Remove a person from the ArrayCollection. */ public function removePerson():void { /* Make sure an item is selected. */ if (dg.selectedIndex >= 0) { ac.removeItemAt(dg.selectedIndex); } } /* Update an existing person in the ArrayCollection. */ public function updatePerson():void { /* Make sure an item is selected. */ if (dg.selectedItem !== null) { ac.setItemAt({first:firstInput.text, last:lastInput.text, email:emailInput.text}, dg.selectedIndex); } } /* The change event listener for the DataGrid. Clears the text input controls and updates them with the contents of the selected item. */ public function dgChangeHandler():void { clearInputs(); firstInput.text = dg.selectedItem.first; lastInput.text = dg.selectedItem.last; emailInput.text = dg.selectedItem.email; } /* Clear the text from the input controls. */ public function clearInputs():void { firstInput.text = ""; lastInput.text = ""; emailInput.text = ""; } ]]> </fx:Script> <s:Panel title="Master-Detail View" width="100%"> <s:layout> <s:VerticalLayout/> </s:layout> <mx:DataGrid width="100%" id="dg" dataProvider="{ac}" change="dgChangeHandler()"> <mx:columns> <mx:DataGridColumn dataField="first" headerText="First Name"/> <mx:DataGridColumn dataField="last" headerText="Last Name"/> <mx:DataGridColumn dataField="email" headerText="Email"/> </mx:columns> </mx:DataGrid> <!-- Form for data to add or change in the ArrayCollection. --> <mx:Form label="test" width="100%"> <mx:FormItem label="First Name" width="100%"> <s:TextInput id="firstInput" width="100%"/> </mx:FormItem> <mx:FormItem label="Last Name" width="100%"> <s:TextInput id="lastInput" width="100%"/> </mx:FormItem> <mx:FormItem label="Email" width="100%"> <s:TextInput id="emailInput" width="100%"/> </mx:FormItem> </mx:Form> <s:HGroup horizontalAlign="center"> <!-- Buttons to initiate operations on the collection. --> <s:Button label="Add New" click="addPerson()"/> <s:Button label="Update Selected" click="updatePerson()"/> <s:Button label="Remove Selected" click="removePerson()"/> <!-- Clear the text input fields. --> <s:Button label="Clear" click="clearInputs()"/> </s:HGroup> </s:Panel> <!-- The application displays event information here --> <s:Panel title="Change log" width="100%" height="125"> <s:TextArea id="log" width="100%" height="100%"/> </s:Panel> </s:Application>

 
For more information