Beruflich Dokumente
Kultur Dokumente
Adobe
Products Solutions Learning Help Downloads Company
Store
Adobe Store for home and home office
Education Store for students, educators, and staff
Business Store for small and medium businesses
Other ways to buy
Search
Search
Search
Info Sign in
Welcome, OC_RupeshMy cart My shipments My support
My account
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions,
community areas, and more.
devnet:flex en_us
Bottom of Form
Adobe Developer Connection / Flex Developer Center /
Created
21 March 2010
Page Tools
Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Tags
Flex
Requirements
User level
All
Adding, updating, and deleting data
Note: Instead of using the RemoteObject class directly as in this sample, you can also use Flash
Builder's Create Data Service wizard to create a data service and then call methods of a generated
service class that wraps the RemoteObject class. Flash Builder introspects the server-side class file
and creates a corresponding client-side class with the same operations. (For this introspection and
code generation to occur, RDS must be enabled on your server.) If the server returns strongly typed
objects (which is the case for the Java classes in this sample), ActionScript classes are created that
map to the corresponding objects manipulated by the methods of the class. If the server returns
general objects (which is the case for the PHP class and CFC in this sample), you can configure the
data service to create typed ActionScript objects whose properties match those for the general
objects returned from the server. Of course, you can also write your PHP classes and CFC methods
to return strongly typed objects instead of general objects as well. After creation, the data service, its
methods, its argument types, and its return types are displayed in the Data/Services view and
methods can be dragged and dropped on components in the application to add them. The Test Drive
tutorials create and use data services created with the Flash Builder Data Service wizard.
Retrieving data
Next, let's look at the calls to the server. We want to retrieve the employee and department data on
application startup. To do this, you usually specify an event handler for the Application object's
initialize or creationComplete events. Every Flex component has a series of events that are
broadcast as the component is created, from the time it is instantiated until the time it is drawn on the
Flash Player drawing surface. The initialize event is broadcast after the component has been
created and all of its properties are set and those of its subojects. creationComplete is broadcast
later after the component and all its subojects also have sizes and positions. Use creationComplete if
any of the code references any sizes or positions.
In the sample code, a handler is specified for the Application's initialize event:
<s:Application initialize="init()" ...>
... and inside the handler, the getEmployees() and getDepartments() methods of the service object
are called.
protected function init():void { getEmployeesResult.token =
employeeService.getEmployees(); getDepartmentsResult.token =
employeeService.getDepartments(); }
When this code is executed, Flash Player makes a call to the server. This happens asynchronously in
the background; the user can still interact with the application.
When you make a service call, you need to specify what Flash Player should do when it gets a result
or error back from the server. A fault handler was specified for the data service itself and will be
used to display errors returned from calls to any of its operations in a popup box.
Using call responders to specify callbacks
To handle successful results, CallResponder objects are declared for each of the calls.
<fx:Declarations> <s:CallResponder id="getEmployeesResult" .../> <s:CallResponder
id="getDepartmentsResult"/> (...) </fx:Declarations>
These need to be associated with the corresponding service call. When a service call is initiated, an
instance of the AsyncToken class is created. To associate the CallResponder object with the service
call, you set the CallResponder's token property equal to the AsyncToken generated at the time the
service call is made. When data is returned from the server, it is handled by that CallResponder.
getEmployeesResult.token=employeeService.getEmployees();
A CallResponder object has a lastResult property that automatically gets populated with the data
when it is returned to Flash Player from the server. It can be easily used by binding a control to it. In
the application, the dataProvider property of a DataGrid component is bound to the lastResult
property of the getDepartmentsResult CallResponder object. Whenever the value of
getDepartmentsResult.lastResult changes, the DataGrid's dataProvider property is updated and
the DataGrid repopulates itself with the new data.
<mx:DataGrid id="deptDg" dataProvider="{getDepartmentsResult.lastResult}" ...>
<mx:columns> <mx:DataGridColumn headerText="Name" dataField="name" width="170"/>
<mx:DataGridColumn headerText="ID" dataField="id" width="40"/> <mx:DataGridColumn
headerText="Manager" dataField="manager" width="170"/> <mx:DataGridColumn
dataField="budget" headerText="Budget" width="155"/> <mx:DataGridColumn
dataField="actualexpenses" headerText="Expenses" width="155"/> </mx:columns>
</mx:DataGrid>
By default, one column is created for each of the fields in the objects used to populate the DataGrid.
You control what properties to display and in what order by setting the columns property equal to an
array of DataGridColumn objects. For each DataGridColumn object, you specify what property it
should display (dataField), the title for the column (header-text), its size, and more.
Using the CallResponder lastResult property works fine if you just want to bind the results to a
component as shown here, but many times you will want to execute some code when the results are
returned. To do this, you register to listen for the result or fault events for the CallResponder. In the
sample, a result handler is registered for the getEmployeesResult CallResponder.
<s:CallResponder id="getEmployeesResult"
result="getEmployeesResult_resultHandler(event)"/>
... and the getEmployeesResult_resultHandler() defined.
Handling return data
This application manipulates employee data. When you bind controls to collections of objects (as we
just saw in the deptDg DataGrid and will see next for the empDg DataGrid), the data should be strored
in a Flex collection class. For example, instead of storing the employee data objects in an Array (a top
level data type in Flash Player), you should use an ArrayCollection. The ArrayCollection basically
wraps an Array so that when any value in any position of the array changes, an event is broadcast
and any controls bound to it will be updated. If the objects were stored in an Array, even if it was
made bindable, events would be broadcast only when the value of the entire array changed, for
example, if it went from null to a value or was set to an entirely different value.
In this application, an employees ArrayCollection is defined in the Declarations block:
<s:ArrayCollection id="employees"/>
... which is equivalent to setting a public, bindable variable in ActionScript:
[Bindable]public var employees:ArrayCollection;
The dataProvider property of the empDg DataGrid is bound to this collection.
<mx:DataGrid id="empDg" dataProvider="{employees}" ...>
Inside this collection, we want to store strongly typed, bindable Employee objects, not general
Objects. This way we will get code-hinting when manipulating these objects and compiler and runtime
property and property type checking. These objects will also be bindable, so if any of their properties
change, an event will be broadcast and any objects bound to it updated.
If you look in the valueObjects folder, you will see an Employee class definition.
package valueObjects { [Bindable] //if server was returning typed objects like for
java, ///[RemoteClass(alias="services.Employee")] public class Employee { public var
id:uint; public var firstname:String; public var lastname:String; //other property
declarations public function Employee() { } } }
If the server-side class returns strongly typed objects (as does the Java class in this sample), you
need to include a RemoteClass metadata tag that maps this ActionScript class to the corresponding
class on the server.
[RemoteClass(alias="services.Employee")]
This is the crucial information needed by Flash Player so it can map the server-side objects to the
correct client-side objects automatically. In this case, the getEmployeeResult_resultHandler() only
needs to populate the employees ArrayCollection with the data returned from the server because the
data has already been translated to an ArrayCollection of Employee objects.
protected function getEmployeesResult_resultHandler(event:ResultEvent):void
{ employees=event.result as ArrayCollection; }
The data returned from a server-side method call is stored in the result property of the event object
that is passed to the result event handler. The employees variable is data typed as an
ArrayCollection but the result property of the event object is data typed as a general Object, so you
have to cast event.result to an ArrayCollection to assign it to employees.
To see what types of ActionScript objects the returned server-side data objects are converted to,
place a breakpoint inside the result handler and debug the application. You can also look at tables of
the data type mappings for ActionScript and Java, ActionScript and PHP, or ActionScript and
ColdFusion.
If Employee objects are not returned from the server (as is the case for the PHP class and CFC in
this sample), getEmployeesResult_resultHandler() needs to create this collection of Employee
objects manually. For PHP, you get an Array of Objects back from the server and for ColdFusion, an
ArrayCollection of Objects. To convert the Objects into Employee objects, you need to loop through
the collection, creating a new Employee instance for each item and populating its properties with the
corresponding properties of the general Object, and then adding that Employee object to the
collection. You could explicitly write each property assignment:
emp.id=data[i].id;
emp.firstname=data[i].firstname;
emp.lastname=data[i].lastname;
//do the same for all properties
... but this code instead uses the describeType() method (in the flash.utils package). describeType()
returns an XML object that contains an accessor element (which has name, access, type, and
declaredBy attributes) for each of object's properties. This is the ActionScript implementation of
reflection.
For ColdFusion, the getEmployeesResult_resultHandler() appears as shown here.
protected function getEmployeesResult_resultHandler(event:ResultEvent):void { var
data:ArrayCollection=event.result as ArrayCollection; for(var i:uint=0; i<data.length; i+
+) { var emp:Employee=new Employee(); for each(var field:XML in
describeType(emp)..accessor){ emp[field.@name]=data[i][field.@name]; }
employees.addItem(emp); } }
The ArrayColletion addItem() method is used to add the new employee to the employees
ArrayCollection.
The handler is slightly different for PHP because you get an Array instead of an ArrayCollection back
from the server.
protected function getEmployeesResult_resultHandler(event:ResultEvent):void { var
data:ArrayCollection=new ArrayCollection(event.result as Array); for(var i:uint=0;
i<data.length; i++) { var emp:Employee=new Employee(); for each(var field:XML in
describeType(emp)..accessor){ emp[field.@name]=data[i][field.@name]; }
employees.addItem(emp); } }
Displaying details
When the user selects an employee in the DataGrid, that employee's details are displayed beneath it.
In the Declarations block, you'll see an employee variable defined of type Employee (that is bindable
by default).
<valueObjects:Employee id="employee"/>
Beneath the Declarations block, you'll see a Binding tag:
<fx:Binding source="empDg.selectedItem as Employee" destination="employee"/>
This is just another way to create a binding between two variables without using {} in an MXML tag.
Whenever the selectedItem property of empDg changes, the employee variable is updated.
As well, there is code to listen for the DataGrid's change event:
<mx:DataGrid id="empDg" dataProvider="{employees}"
includeIn="EmployeeAdd,EmployeeDetails,EmployeeUpdate,Employees"
change="empDg_changeHandler(event)" ...>
Inside the change handler, you switch to the application's EmployeeDetails state:
protected function
empDg_changeHandler(event:ListEvent):void{ currentState="EmployeeDetails"; }
... that includes a Form container that has one Label control for each of the employee object's
properties.
<mx:Form includeIn="EmployeeDetails" x="63" y="325"> <mx:FormItem label="Last Name">
<s:Label id="lastnameLabel" text="{employee.lastname}"/> </mx:FormItem> <mx:FormItem
label="First Name"> <s:Label id="firstnameLabel" text="{employee.firstname}"/>
</mx:FormItem> (...) </mx:Form>
The employee details will be displayed in the Label controls in the Form. A Flex Form container is
purely a layout container, helping to easily line up multiple controls that have labels in front of them; it
has no other purpose like in an HTML form. When you send data to the server which we will look at
next, you specify explicity what objects to send; they have nothing to do with Form components.
Now that we have seen how to retrieve and display data from the server, let's look at how to modify
this data on the server, updating, adding, and deleting records in the database. You may want to go
look at your application server's class file (or CFC) now to familiarize yourself with the methods it
contains before looking at the code to call these methods. If you installed the files, you can look at the
source code on your server. Otherwise, you can right-click the SWF in the browser, select View
Source, and browse to the appropriate PHP class, Java class, or CFC.
Using the DataGrid to update data
One way to let users update the data is to make the DataGrid editable and then to send the changes
to the server. You make the DataGrid editable by setting its editable property to true and then
registering to listen for its itemEditEnd event which is broadcast when the user gives focus to a cell
and then moves away.
<mx:DataGrid id="empDg" dataProvider="{employees}" editable="true"
itemEditEnd="empDg_itemEditEndHandler(event)" ...>
Inside the handler, you need to send the modified Employee instance to the server: call the
updateEmployee() method and pass to it the selected item in the DataGrid.
employeeService.updateEmployee(employee);
For ColdFusion, you need to modify this slightly. When you pass an object to a Flash Remoting
request, it is treated as a group of named arguments and passed to the CFC method as individual
arguments, not as a single object argument. To actually pass a single object as an argument, you
must create an Object instance with the name of the argument expected by the CFC, in this case an
argument called item, and pass that to the server-side method. The {} her are are an ActonScirpt
short hand notation for creating an Object; multiple name/value pairs would be separated by commas.
employeeService.updateEmployee({item:employee});
In this case, you're not going to do anything after the data is successfully updated so you don't need
to specify a CallResponder to handle the results.
If you ran this code and made changes in the DataGrid, the new values would not be saved to the
database because the itemEditEnd event is broadcast after the user has finished editing a cell but
before the DataGrid has updated its dataProvider with the new value. You need to update the
employee object with the new property value before sending it to the server:
employee[event.dataField]= (empDg.itemEditorInstance as mx.controls.TextInput).text;
... where event.dataField is a reference to the property of the object being edited, for example
"firstname" and empDg.itemEditorInstance is a reference to the component being used in the
DataGrid cell to get the new data from the user, in this case a TextInput control which has a text
property. The newly entered value will be available in the text property of this object.
Here is the complete code for the handler.
protected function empDg_itemEditEndHandler(event:DataGridEvent):void
{ employee[event.dataField]=(empDg.itemEditorInstance as mx.controls.TextInput).text;
//for Java and PHP employeeService.updateEmployee(employee);> //for
CF,employeeService.updateEmployee({item:employee}); }
In this application, updates are sent to the server every time the user changes data in one DataGrid
cell. If a lot of changes are going to be made, you may want to wait and submit all changes to the
server at once.
Using a form to update data
Only some of the employee data is displayed in the DataGrid, so you may also want to provide a form
for the user to modify all of the employee data.
When an employee is selected and the EmployeeDetails state displayed, an update button is
enabled.
<s:Button id="updateBtn" includeIn="EmployeeAdd,EmployeeDetails,EmployeeUpdate"
label="Update" enabled.EmployeeAdd="false" enabled.EmployeeUpdate="false"
click="updateBtn_clickHandler(event)" .../>
When the user clicks this button, the application switches to its EmployeeUpdate state:
protected function
updateBtn_clickHandler(event:MouseEvent):void{ currentState="EmployeeUpdate"; }
... that has a Form containing one TextInput control for each of the employee properties that can be
updated.
<mx:Form includeIn="EmployeeAdd,EmployeeUpdate" defaultButton="{button}"...> <mx:FormItem
label="Last Name"> <s:TextInput id="lastnameTextInput" text="{employee.lastname}"/>
</mx:FormItem> <mx:FormItem label="First Name"> <s:TextInput id="firstnameTextInput"
text="{employee.firstname}"/> </mx:FormItem> <!-- more FormItem controls -->
<mx:FormItem> <s:Button id="button" label="Add" click="button_clickHandler(event)"
label.EmployeeUpdate="Update"/> </mx:FormItem> </mx:Form>
When the user clicks this button in the Form container, the employee object is updated with the
values the user entered in the input controls and then passed to the data service's updateEmployee()
method.
protected function button_clickHandler(event:MouseEvent):void { employee.lastname =
lastnameTextInput.text; employee.firstname = firstnameTextInput.text; employee.title =
titleTextInput.text; //code to set the rest of the properties if(employee.id==0){ //for
Java and PHP createEmployeeResult.token = employeeService.createEmployee(employee); //for
CF, createEmployeeResult.token = employeeService.createEmployee({item:employee}); } else{
//for Java and PHP updateEmployeeResult.token = employeeService.updateEmployee(employee);
//for CF, updateEmployeeResult.token = employeeService.updateEmployee({item:employee}); }
}
Similar functionionality will be used to add a new employee next, so this function has been written to
handle both cases. If an existing employee is being updated, employee.id will be non-zero, so the
server-side updateEmployee() method is called. Otherwise, the createEmployee() method is called.
As before, the code for ColdFusion is slightly different to pass an object to a server-side method.
In this case, we do want to do something after the data has successfully been sent to the server, so a
new CallResponder is defined with a result handler:
<s:CallResponder id="updateEmployeeResult"
result="updateEmployeeResult_resultHandler(event)"/>
... and the service call assigned to the CallResponder's token property.
updateEmployeeResult.token=employeeService.updateEmployee(employee);
In the result handler, the application switches to its EmployeeDetails state and shows the details for
the modified employee.
protected function updateEmployeeResult_resultHandler(event:ResultEvent):void
{ currentState="EmployeeDetails"; }
Note: In this example, you are writing code to update both the server-side data (stored in the
database) and the client-side data (stored in the DataGrid dataProvider). Flash Builder also has a
data management feature you can use to help synchronize client and server-side data.
Then, you select it in the DataGrid:
empDg.selectedItem=employee;
... and then scroll to it so it is displayed:
empDg.verticalScrollPosition=empDg.selectedIndex; empDg.validateNow();
For performance reasons, the DataGrid sometimes defers updating its display. The validateNow()
method forces it to update its display. Although appropriate here, be careful using validateNow()
because it can cause performance problems if called too often.
The result event handler for adding an employee appears as shown here.
protected function createEmployeeResult_resultHandler(event:ResultEvent):void
{ currentState="EmployeeDetails"; employee.id=event.result as int;
employees.addItem(employee); empDg.selectedItem =employee;
empDg.verticalScrollPosition=empDg.selectedIndex; empDg.validateNow(); }
Deleting data
The last thing to look at is how to delete an employee from the database. The process is very similar
to those for adding and updating. When an employee is selected, a delete button is enabled.
<s:Button id="deleteBtn" click="deleteBtn_clickHandler(event)"
enabled.EmployeeAdd="false" includeIn="EmployeeAdd,EmployeeDetails,EmployeeUpdate"
label="Delete" enabled.EmployeeUpdate="true"/>
When the user clicks this button, the server-side deleteEmployee() method is called.
protected function deleteBtn_clickHandler(event:MouseEvent):void
{ deleteEmployeeResult.token = employeeService.deleteEmployee(employee.id); }
To handle results, a new CallResponder is defined with a result handler:
<s:CallResponder id="deleteEmployeeResult"
result="deleteEmployeeResult_resultHandler(event)"/>
... and the service call assigned to the CallResponder's token property.
deleteEmployeeResult.token=employeeService.deleteEmployee(employee.id);
The server-side method expects one argument, the id of the employee to delete.
In the result handler, the employee is removed from the employees ArrayCollection using its
removeItemAt() method and the application is switched to its Employees state (there is no longer any
employee selected to show details for).
protected function deleteEmployeeResult_resultHandler(event:ResultEvent):void
{ employees.dataProvider.removeItemAt(empDg.selectedIndex); currentState="Employees"; }
Back to top
+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0
Unported License. Permissions beyond the scope of this license, pertaining to the examples of code
included within this work are available at Adobe.
Choose your region United States (Change)
Choose your region Close
North America
Canada - English
Canada - Français
Latinoamérica
México
United States
South America
Brasil
Africa
Africa - English
Middle East and North Africa - English
Europe
Österreich - Deutsch
Belgium - English
Belgique - Français
België - Nederlands
България
Hrvatska
Česká republika
Danmark
Eastern Europe - English
Eesti
Suomi
France
Deutschland
Magyarország
Ireland
Italia
Latvija
Lietuva
Luxembourg - Deutsch
Luxembourg - English
Luxembourg - Français
Nederland
Norge
Polska
Portugal
România
Россия
Srbija
Slovensko
Slovenija
España
Sverige
Schweiz - Deutsch
Suisse - Français
Svizzera - Italiano
Türkiye
Україна
United Kingdom
Asia Pacific
Australia
中国
中國香港特別行政區
Hong Kong S.A.R. of China
India - English
日本
한국
New Zealand
Pacific - English
台灣
Southeast Asia
Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English
Security Contact Adobe Report piracy EULAs Permissions and trademarks Careers
Copyright © 2011 Adobe Systems Incorporated. All rights reserved.
Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy (updated
07-14-2009).
close