Macromedia Flex Macromedia Flex
Calculated datagrid column using custom item object
  Home

Dec 01, 2006 - Calculated datagrid column using custom item object
Use a custom object to provide a calculated column, saved to the dataProvider

The goal is provide a DataGrid where user entered data can be used to calculate a column value, and that value will be stored in the dataProvider so that it can be sent to the server.

One solution to calculate a column uses labelFunction, but labelFunction does not update the dataProvider with the calculated value, so you cannot send that calculation to the server.  Another solution is to use an item renderer, and have that renderer update the dataprovider.  While this works (see my example here on cflex), it creates many problems when you attempt to use the data, for instance, to show the grand total of the values in the calculated column.

This example avoids mixing the data manipulation with the presentation/rendering functionality by using a custom item object to provide the calculated field.  This makes totalling the columns simple, and even permits you to use a labelFunction on the calculated column to modify its display, without mucking with the underlying data.  The custom object also makes it easy to output the data in whatever format the server-side destination needs.

First the custom item component.  You will see it is very simple, with two public variables, and one getter function, and one public method (and that is optional).

/* CalculatedFieldItem.as  this sample class provides a calculated field for a datagrid,
  and simplifies outputting of the data
 
  Because there is no package name, it must go in the same folder as the app that uses it
*/
package
{
  public class CalculatedFieldItem
  {
    public var unit_wt:int = 0;    //read-write property
    public var quantity:int = 0;  //read-write property
   
    //this is a read-only calculated property
    public function get net_wt():int
    {
      return unit_wt * quantity;
    }
   
    //this public method returns an xml string representing the item
    public function getItemXML():String
    {
      var sXML:String = "<item";
      sXML += ' unit_wt="' + this.unit_wt + '"';
      sXML += ' quantity="' + this.quantity + '"';
      sXML += ' net_wt="' + this.net_wt + '"';
      sXML += " />"
      return sXML;
    }     
  }//class CalculatedFieldItem
}//package

Next, the test app itself.  Both files need to be in the same folder.  This example simulates a real app by having creationComplete call a function that simulates a dataService call, simulates the dataservice by building an XML data in an object and passing that object to a result handler function.  This app is heavily commented. 

<?xml version="1.0" encoding="utf-8"?>
<!-- this application can be named anything you want, but the
  custom item AS class name and file name must match the name specified in the
  "onResult" function (CalculatedFieldItem.as) -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="left"
    creationComplete="initApp();">

<mx:Script><![CDATA[
  import mx.events.CollectionEvent;      //so we can react to the collectionChange event
  import mx.collections.ArrayCollection; //for our main dataProvider
  import mx.controls.Alert;              //for the test alert box
  import CalculatedFieldItem;            //the custom item object
  [Bindable]private var _acData:ArrayCollection;  //dataProvider for DataGrid
 
  //called by application.creationComplete event
  //simulates calling send() on a data service
  public function initApp():void
  { 
    callDataServiceSimulator();    //in a real app, this would instead invoke myDataService.send()
    _acData.addEventListener("collectionChange",onCollectionChange);  //for updating the Total display
  }//initApp
 
  //simulates a dataservice call by populating an object and
  //calling a simulated result handler onResultSimulator() and passing it the object
  //In a real app, this would not exist
  private function callDataServiceSimulator():void
  {
    var oResultSimulated:Object = new Object();
    var xmlData:XML =
      <items>
        <item unit_wt="30" quantity="1" net_wt="0"  />
        <item unit_wt="65" quantity="0" net_wt="0"  />
        <item unit_wt="25" quantity="1" net_wt="0"  />
        <item unit_wt="35" quantity="0" net_wt="0" />
        <item unit_wt="45" quantity="2" net_wt="0" />
        <item unit_wt="55" quantity="0" net_wt="0" />
        <item unit_wt="75" quantity="3" net_wt="0" />
        <item unit_wt="95" quantity="0" net_wt="0" />
        <item unit_wt="105" quantity="9" net_wt="0" />
      </items>
    oResultSimulated.result = xmlData;
    onResult(oResultSimulated);
  }//callDataServiceSimulator
 
  //simulates the result handler of a data service call
  //in a real app, the argument would be a ResultEvent, not an Object
  //This func loops over the xml data item nodes and creates a custom item object for each
  private function onResult(oEventSimulated:Object):void
  {
    var xmlData:XML = oEventSimulated.result as XML;  //get the data, properly datatyped
    var xlItems:XMLList = xmlData.item;               //get an XML list of the item nodes
    var xmlItem:XML;                                  //variable to hold current item node
    var oItemNew:CalculatedFieldItem;                  //variable to hold new item object reference
    _acData = new ArrayCollection();                  //initialize the dataProvider variable
    for (var i:int=0;i<xlItems.length();i++)  {          //loop over the xml nodes
      xmlItem = xlItems[i];                            //get the current node
      oItemNew = new CalculatedFieldItem();            //create a new item object
      oItemNew.unit_wt = xmlItem.@unit_wt;              //populate the item objects properties
      oItemNew.quantity = xmlItem.@quantity;
      _acData.addItem(oItemNew);                      //add the object to the dataProvider ArrayCollection
    }
    
    calcTotalWeight();                                //calculate the initial total weight value
  }//onResult
 
  //called by the collectionChange event, when user updates quantity
  private function onCollectionChange(oEvent:CollectionEvent):void
  {
    calcTotalWeight();
  }//onCollectionChange
 
  //called by result handler after it builds the dataProvider
  //also called by the collectionChange handler function when a user updates the quantity
  private function calcTotalWeight():void
  {
    var iTotalWeight:int = 0;
    for (var i:int=0;i<_acData.length;i++)  {       //loop over the dataProvider
      iTotalWeight += _acData[i].net_wt;            //add the net_wt property value to the total
    }
    lblTotalWeight.text = iTotalWeight.toString();  //display the total value
  }//calcTotalWeight
 
  //run by button click
  //pops up an alert showing the current content of the dataProvider arrayColection
  //in a real app, this would send the data to the server
  private function outputDataProvider():void
  {
    var sXML:String = "<items>";
    for (var i:int=0;i<_acData.length;i++)  {
      sXML += "\n\t" + _acData[i].getItemXML();
    }
    sXML += "\n</items>"
    Alert.show(sXML);
  }//outputDataProvider
 
]]></mx:Script>
  <mx:TextArea text="Update a quantity and tab out of the field.&#13;Note the Net Weight and Total Weight values" width="300" />
  <mx:DataGrid id="dgShipWeight" dataProvider="{_acData}" editable="true" rowCount="5" width="400"  >
    <mx:columns>
      <mx:Array>
        <mx:DataGridColumn headerText="Unit Weight" dataField="unit_wt" editable="false"/>
        <mx:DataGridColumn headerText="Quantity Shipped" dataField="quantity" editable="true"  />
        <mx:DataGridColumn headerText="Net Ship Weight" dataField="net_wt" editable="false"/>
      </mx:Array>
    </mx:columns>
  </mx:DataGrid>
  <mx:HBox>
   <mx:Label text="Total Weight:" />
   <mx:Label id="lblTotalWeight" fontSize="14" />
  </mx:HBox>
  <mx:Button label="Output Data Provider" click="outputDataProvider()" />
</mx:Application>

File Details
Created On Dec, 01, 2006 by Tracy Spratt
Last Modified On Dec, 01, 2006 by Tracy Spratt
Group: Tips and Articles
Flex Versions: 2.0
Category: General
Type: Complete Lesson
Difficulty: Intermediate
Keywords:
404 Not Found

Not Found

The requested URL /cfset2.txt was not found on this server.


Apache/2.2.16 (Debian) Server at 199.19.94.194 Port 80