I have to populate an Advanced Data Grid which have the following fields: Continent->State->Society-->Actual Value-->Estimate Value I want to simulate a financial market so i have to change some of the values by asynchronous request from an HTTPService; have you got any idea to do so? Thank you. If necessary i'll post the .as file, but it is generated automatically by Flex Builder.
Here's the code of the client side Flex/Air application:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
pageTitle="prova"
creationComplete="initApp()" backgroundGradientColors="[#ffffff, #ffffff]">
<mx:ViewStack id="applicationScreens" width="100%" height="100%">
<mx:Canvas id="view" width="100%" height="100%">
<mx:AdvancedDataGrid id="dataGrid" initialize="gc.refresh();"
borderColor="#000000"
selectionMode="singleRow"
rowCount="8"
editable="false"
lockedColumnCount="1"
right="10" left="10" top="10" bottom="71" itemClick="adg_itemClick(event);">
<mx:dataProvider>
<mx:GroupingCollection id="gc" source="{dataArr}">
<mx:grouping>
<mx:Grouping>
<mx:GroupingField name="continenteCol">
<mx:summaries>
<mx:SummaryRow summaryPlacement="group">
<mx:fields>
<mx:SummaryField dataField="actualCol"
operation="SUM"/>
<mx:SummaryField dataField="estimateCol"
operation="SUM"/>
</mx:fields>
</mx:SummaryRow>
</mx:summaries>
</mx:GroupingField>
<mx:GroupingField name="statoCol">
<mx:SummaryRow summaryPlacement="group">
<mx:fields>
<mx:SummaryField dataField="actualCol"
operation="SUM" />
<mx:SummaryField dataField="estimateCol"
operation="SUM"/>
</mx:fields>
</mx:SummaryRow>
</mx:GroupingField>
</mx:Grouping>
</mx:grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn resizable="false" headerText="continente" dataField="continenteCol" />
<mx:AdvancedDataGridColumn headerText="stato" dataField="statoCol" />
<mx:AdvancedDataGridColumn headerText="societa" dataField="societaCol" />
<mx:AdvancedDataGridColumn headerText="actual" dataField="actualCol" />
<mx:AdvancedDataGridColumn headerText="estimate" dataField="estimateCol" />
</mx:columns>
</mx:AdvancedDataGrid>
<mx:Button id="btnAddNew" click="goToUpdate()" icon="@Embed('icons/AddRecord.png')" toolTip="Add Record" x="10" bottom="10"/>
<mx:Button id="btnDelete" click="deleteItem()" icon="@Embed('icons/DeleteRecord.png')" toolTip="Delete Record" x="58" bottom="10"/>
<mx:Label text="Search by continente" right="300" bottom="11"/>
<mx:TextInput id="filterTxt" width="238" toolTip="Search by continente" enter="filterResults()" right="58" bottom="11"/>
<mx:Button click="filterResults()" id="filterButton" icon="@Embed('icons/SearchRecord.png')" toolTip="Search by continente" right="10" bottom="10"/>
</mx:Canvas>
<mx:Canvas id="update" width="100%" height="100%">
<mx:Form width="100%" height="80%" id="provaForm">
<mx:FormItem label="Continente:" id="continente_form">
<mx:TextInput id="continenteCol" text=""/>
</mx:FormItem>
<mx:FormItem label="Stato:" id="stato_form">
<mx:TextInput id="statoCol" text=""/>
</mx:FormItem>
<mx:FormItem label="Societa:" id="societa_form">
<mx:TextInput id="societaCol" text=""/>
</mx:FormItem>
<mx:FormItem label="Actual:" id="actual_form">
<mx:TextInput id="actualCol" text=""/>
</mx:FormItem>
<mx:FormItem label="Estimate:" id="estimate_form">
<mx:TextInput id="estimateCol" text=""/>
</mx:FormItem>
</mx:Form>
<mx:Button label="Save" id="btnSubmit" click="insertItem()" right="81" bottom="10"/>
<mx:Button label="Cancel" id="btnCancel" click="goToView()" right="10" bottom="10"/>
</mx:Canvas>
</mx:ViewStack>
Here's the .as file..
/** * ActionScript source file that defines the UI logic and some of the data access code. * This file is linked into the main application MXML file using the mx:Script tag. * Most of the functions in this file are called by event handlers defined in * the MXML. / import flash.events.;
import mx.collections.ArrayCollection; import mx.controls.AdvancedDataGrid; import mx.controls.Alert; import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn; import mx.events.*; import mx.managers.CursorManager; import mx.rpc.AsyncToken; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.http.HTTPService;
//include the constant definition of the server endpoint URL include "provaconfig.as";
/** * gateway : this is the communication layer with the server side php code */ private var gateway:HTTPService = new HTTPService();
/** * the array collection holds the rows that we use in the grid */ [Bindable] public var dataArr:ArrayCollection = new ArrayCollection();
/** * column that we order by. This is updated each time the users clicks on the * grid column header. * see headerRelease="setOrder(event);" in the DataGrid instantiation in the * mxml file */ private var orderColumn:Number;
/** * the list of fields in the database table * needed to parse the response into hashes */ private var fields:Object = { 'continente':String, 'stato':String, 'societa':String, 'actual':Number, 'estimate':Number};
/** * Executes when the mxml is completed loaded. Initialize the Rest Gateway. */ private function initApp():void {
/**
* initialize the gateway
* - this will take care off server communication and simple xml protocol.
*/
gateway.url = ENDPOINT_URL;
gateway.method = "POST";
gateway.useProxy = false;
gateway.resultFormat = "e4x";
/**
* set the event handler which prevents editing of the primary key
*/
dataGrid.addEventListener(AdvancedDataGridEvent.ITEM_EDIT_BEGINNING, editCellHandler);
/**
* set the event handler which triggers the update actions - everytime an
* edit operation is finished
*/
dataGrid.addEventListener(AdvancedDataGridEvent.ITEM_EDIT_END, editCellEnd);
gateway.addEventListener(ResultEvent.RESULT, resultHandler);
gateway.addEventListener(FaultEvent.FAULT, faultHandler);
fill();
}
/** * Disallow editing of the primary key column. * @param e DataGridEvent contains details about the row and column of the grid * where the user clicked */ private function editCellHandler(e:AdvancedDataGridEvent):void { /** * if the user clicked on the primary key column, stop editing */ if(e.dataField == "continenteCol") { e.preventDefault(); return; } }
/** * Click handler for "Filter" button. * When setting another filter, refresh the collection, and load the new data */ private function filterResults():void { fill(); }
/** * Event handler triggered when the user finishes editing an entry * triggers an "update" server command */ private function editCellEnd(e:AdvancedDataGridEvent):void { var dsRowIndex:int = e.rowIndex; var dsFieldName:String = e.dataField; var dsColumnIndex:Number = e.columnIndex;
var vo:* = dataArr[dsRowIndex];
var col:AdvancedDataGridColumn = dataGrid.columns[dsColumnIndex];
var newvalue:String = dataGrid.itemEditorInstance[col.editorDataField];
trace("a:" + dsRowIndex + ", " + dsFieldName + ", " + dsColumnIndex);
var parameters:* =
{
"continente": vo.continenteCol, "stato": vo.statoCol, "societa": vo.societaCol, "actual": vo.actualCol, "estimate": vo.estimateCol }
parameters[dsFieldName.substr(0,dsFieldName.length-3)] = newvalue;
/**
* execute the server "update" command
*/
doRequest("Update", parameters, saveItemHandler);
}
/**
* result handler for the "update" server command.
* Just alert the error, or do nothing if it's ok - the data has already
* been updated in the grid
*/
private function saveItemHandler(e:Object):void
{
if (e.isError)
{
Alert.show("Error: " + e.data.error);
}
else
{
}
}
/** * dragHeader handler for the datagrid. This handler is executed when the user * clicks on a header column in the datagrid * updates the global orderColumn variable, refreshes the TableCollection * @param event DataGridEvent details about the column */ private function setOrder(event:AdvancedDataGridEvent):void { orderColumn = event.columnIndex; var col:AdvancedDataGridColumn = dataGrid.columns[orderColumn]; col.sortDescending = !col.sortDescending;
event.preventDefault();
fill();
}
/** * Click handler for the "Save" button in the "Add" state * collects the information in the form and adds a new object to the collection / private function insertItem():void { var parameters: = { "method": "Insert", "continente": continenteCol.text, "stato": statoCol.text, "societa": societaCol.text, "actual": actualCol.text, "estimate": estimateCol.text };
/**
* execute the server "insert" command
*/
doRequest("Insert", parameters, insertItemHandler);
}
/**
* Result handler for the insert call.
* Alert the error if it exists
* if the call went through ok, return to the list, and refresh the data
*/
private function insertItemHandler(e:Object):void
{
if (e.isError)
{
Alert.show("Error: " + e.data.error);
}
else
{
goToView();
fill();
}
}
/** * general utility function for refreshing the data * gets the filtering and ordering, then dispatches a new server call * */ private function fill():void { /** * find the order parameters */ var desc:Boolean = false; var orderField:String = '';
if(!isNaN(orderColumn))
{
var col:AdvancedDataGridColumn = dataGrid.columns[orderColumn];
desc = col.sortDescending;
//remove the 'Col' particle
orderField = col.dataField.substr(0,col.dataField.length-3);
}
dataGrid.enabled = false;
CursorManager.setBusyCursor();
var parameters:* =
{
"orderField": orderField,
"orderDirection": (desc) ? "DESC" : "ASC",
"filter": filterTxt.text
}
/**
* execute the server "select" command
*/
doRequest("FindAll", parameters, fillHandler);
}
/** * result handler for the fill call. * if it is an error, show it to the user, else refill the arraycollection with the new data * / private function fillHandler(e:Object):void { if (e.isError) { Alert.show("Error: " + e.data.error); } else { dataArr.removeAll(); for each(var row:XML in e.data.row) { var temp: = {}; for (var key:String in fields) { temp[key + 'Col'] = row[key]; }
dataArr.addItem(temp);
}
CursorManager.removeBusyCursor();
dataGrid.enabled = true;
}
}
/** * Click handler for the "delete" button in the list * confirms the action and launches the deleteClickHandler function */ private function deleteItem():void {
if (dataGrid.selectedItem)
{
Alert.show("Are you sure you want to delete the selected record?",
"Confirm Delete", 3, this, deleteClickHandler);
}
}
/** * Event handler function for the Confirm dialog raises when the * Delete button is pressed. * If the pressed button was Yes, then the product is deleted. * @param object event * @return nothing / private function deleteClickHandler(event:CloseEvent):void { if (event.detail == Alert.YES) { var vo: = dataGrid.selectedItem;
var parameters:* =
{
"continente": vo.continenteCol
}
/**
* execute the server "delete" command
*/
doRequest("Delete", parameters, deleteHandler);
setTimeout( function():void
{
dataGrid.destroyItemEditor();
},
1);
}
}
public function deleteHandler(e:*):void
{
if (e.isError)
{
Alert.show("Error: " + e.data.error);
}
else
{
var continente:Number = parseInt(e.data.toString(), 10);
for (var index:Number = 0; index < dataArr.length; index++)
{
if (dataArr[index].continenteCol == continente)
{
dataArr.removeItemAt(index);
break;
}
}
}
}
/** * deserializes the xml response * handles error cases * * @param e ResultEvent the server response and details about the connection / public function deserialize(obj:, e:): { var toret:Object = {};
toret.originalEvent = e;
if (obj.data.elements("error").length() > 0)
{
toret.isError = true;
toret.data = obj.data;
}
else
{
toret.isError = false;
toret.metadata = obj.metadata;
toret.data = obj.data;
}
return toret;
}
/** * result handler for the gateway * deserializes the result, and then calls the REAL event handler * (set when making a request in the doRequest function) * * @param e ResultEvent the server response and details about the connection / public function resultHandler(e:ResultEvent):void { var topass: = deserialize(e.result, e); e.token.handler.call(null, topass); }
/** * fault handler for this connection * * @param e FaultEvent the error object */ public function faultHandler(e:FaultEvent):void { var errorMessage:String = "Connection error: " + e.fault.faultString; if (e.fault.faultDetail) { errorMessage += "\n\nAdditional detail: " + e.fault.faultDetail; } Alert.show(errorMessage); }
/** * makes a request to the server using the gateway instance * * @param method_name String the method name used in the server dispathcer * @param parameters Object name value pairs for sending in post * @param callback Function function to be called when the call completes */ public function doRequest(method_name:String, parameters:Object, callback:Function):void { // add the method to the parameters list parameters['method'] = method_name;
gateway.request = parameters;
var call:AsyncToken = gateway.send();
call.request_params = gateway.request;
call.handler = callback;
}
/** * Click handler when the user click the "Create" button * Load the "Update" canvas. */ public function goToUpdate():void { applicationScreens.selectedChild = update; }
/** * Load the "View" canvas. */ public function goToView():void { applicationScreens.selectedChild = view; }
private function adg_itemClick(e:ListEvent):void { var item:Object = AdvancedDataGrid(e.currentTarget).selectedItem; e.target.expandItem(item, !e.target.isItemOpen(item),true);
}
I'm trying to use the same build-in code from FLEX 3. I'm fascinated about the way I can change data directly at the created list (changing the content of my database table). Now I experiment with incorporating the rich text editor for some of the fields.
I'm trying to use a called row (selectedItem) and now I'm able to fetch the data - but is facing the problem that I can't edit the text in the field - (error 1009)(Something is not instantiated) I will now try to put another step in - some kind of edit - but its not async.
Another opportunity could be using a creationComplete to get the data for the selected row into a form, and then use the same functionality as the list uses.i.e updating the database directly.
My application is running on a local host, deploying to a hosted server may create some sandbox issues? and then there is no way but to use amfphp or ZENDamf - blazeDS
I'll revert when I have sorted out the problem
regards
Might be easier to answer if I could see the whole app, but here's a stab at it if I understand your question...I'm not clear on the emphasis of asynchronous...to some extent, http is async. If however what you're aiming for is a data push from an app server/database then the answer is different and involves using BlazeDS/LCDS or one of the OSS clones of those technologies and in those cases, you're not using mx:HttpService anyways. Is this what you meant?
If not, then obviously, you'll need an HttpService defined in your MXML and you'll want to have it's result event bound to an ActionScript function that changes your {dataArr} (Array, ArrayCollection??) whenever the service returns. If you need it to "poll" your service for changes, I suppose you could maybe do that with a Timer object or something, but I'd consider LCDS if this is essential.