Tuesday, October 7, 2008

Flex DataGrid LookupColumn

Update- 10/27/2008 3:27 pm
Updated the LookupColumn control to search for items via a hash array. The old code would loop through the source for each item witch would make the computation do R*N checks not a has array is created so that only R check's are needed. This makes a big difference is there area are large number rows or lookup items.

I highly recommend updating to this code to make renders run faster.


Here is another useful Flex component. This is a DataGridColumn that can be used to do simple lookups from another source when the DataGrid is rendered. You can use it to full data from a second source without having to first merge the data of write custom label functions.

Here is a simple example:

private const myGroups:ArrayCollection = new ArrayCollection(
[{groupid: 1, name: "Admin"},
{groupid: 2, name: "User"},
{groupid: 3, name: "Guest"}]);

<mx:DataGrid dataProvider="{}">
<mx:columns>
<mx:DataGridColumn headerText="User Name" dataField="username"/>
<LookupColumn headerText="Group" dataField="groupid" labelField="name" source="{myGroups}"/>
</mx:columns>
</mx:DataGrid>

LookupColumn.as
package hines
{
import flash.events.Event;

import mx.collections.ArrayCollection;
import mx.controls.dataGridClasses.DataGridColumn;

[Exclude(name="dataTipField", kind="property")]

/**
* This class is a custom DataGridColumn taht will look up each item in another array and fill in a field from the found item in its place.
*
* Example:
* private const myGroups:ArrayCollection = new ArrayCollection(
* [{groupid: 1, name: "Admin"},
* {groupid: 2, name: "User"},
* {groupid: 3, name: "Guest"}]);
*
* <hines:LookupColumn headerText="Group" dataField="groupid" labelField="groupname" source="{myGroups}"/>
*
* This will cause and rows with a groupid of 1 to render as "Admin" and so on.
*
* This will also work with a xml source and the lookupField can be used if the field names differ.
*
* <hines:LookupColumn headerText="Users Group" dataField="usersgroupid" lookupField="groupid" labelField="groupname" source="{myGroups}"/>
*
* @author jpyne
*/
public class LookupColumn extends DataGridColumn
{
public function LookupColumn(columnName:String=null)
{
super(columnName);

// Set up the internal lableFunction.
labelFunction = LookupColumn.doLookup;
}


//----------------------------------
// labelField
//----------------------------------

private var _labelField:String;

/**
* Field to display in the destination record. If this is not set it will default to "label".
*/
[Inspectable(category="General", defaultValue="")]
[Bindable("labelFieldChanged")]
public function get labelField():String
{
return _labelField ? _labelField : "label";
}

/**
* @private
*/
public function set labelField(value:String):void
{
_labelField = value;

dispatchEvent(new Event("labelFieldChanged"));
}


//----------------------------------
// lookupField
//----------------------------------

private var _lookupField:String;

/**
* Field to search for in the source ArrayCollection. If unset then datafield will be used.
*/
[Inspectable(category="General", defaultValue="")]
[Bindable("lookupFieldChanged")]
public function get lookupField():String
{
return _lookupField ? _lookupField : dataField;
}

/**
* @private
*/
public function set lookupField(value:String):void
{
_lookupField = value;

if(source)
prepSource();

dispatchEvent(new Event("lookupFieldChanged"));
}


//----------------------------------
// source
//----------------------------------

private var _source:ArrayCollection;

/**
* Field to display in the destination record. If this is not set it will default to "label".
*/
[Inspectable(category="General", defaultValue="")]
[Bindable("sourceChanged")]
public function get source():ArrayCollection
{
return _source;
}

/**
* @private
*/
public function set source(value:ArrayCollection):void
{
_source = value;

if(lookupField)
prepSource();

dispatchEvent(new Event("sourceChanged"));
}


//----------------------------------
// hashSource
//----------------------------------

private var _hashSource:Object;

public function get hashSource():Object
{
return _hashSource;
}

private function prepSource():void
{
_hashSource = new Object();

for each (var item:Object in source)
{
_hashSource[item[lookupField]] = item;
}
}


/**
* Override the dataTipFiled and change it to the dataField as that will be hidden.
*/
override public function get dataTipField():String
{
return dataField;
}

/**
* Look for a item in a source and display its labelField. This is an internal method and will be called for each item in teh DataGrid.
*
* @param row
* @param control
* @return
*/
static private function doLookup(row:Object, control:LookupColumn):String
{
if(control.hashSource && control.hashSource[row[control.dataField]])
return control.hashSource[row[control.dataField]][control.labelField];

// If no match was found, just return the original value.
return row[control.dataField];
}
}
}

No comments: