Example of Feature Rich ItemRenderers in Flex
September 15, 2008 – 5:00 pm by SethIn response to some requests I got from friends wanting some more real world ItemRenderer examples, here is one that approaches the item renderer from a graphical approach and brings together some different techniques to create a nicely featured ItemRenderer.
Here is what this example DataGrid/ItemRender demonstrates:
- MXML based ItemRenderer
- Override ItemRenderer ’set data’ have data as a known ValueObject
- Swap icons/images based on data values
- Highlight selected ItemRenderer
- Enable ItemRenderer to dispatch an event to remove a person from the grid
DataProvider and ValueObjects
The first thing we’ll look at in the example is the data and data provider for the Grid. Keep in mind this is just a quick demo way to load sample data, the goal is to create an ArrayCollection of Value Objects. The sample XML data is loaded via an HTTPService. When the result comes back from the service we cast the result as an ArrayCollection, we then loop through each item in that result ArrayCollection. Each item is an Object containing the ‘person’ data defined in the XML. For this example we want to place each person data in a person ValueObject (VO). This VO provides a known data type that we will use as the ‘data’ in the ItemRenderer. Often when using AMF taking to ColdFusion/BlazeDS/Java/Etc the VO will be aliased to a data type on the server, so this example simulates the DataGrid provider being an ArrayCollection of VOs.
This result function populates the DataProvider with our Person VOs:
private function httpResult_handler(evt:ResultEvent):void {
if (evt.result.people.person) {
//result
var resultAC:ArrayCollection = evt.result.people.person as ArrayCollection;
//loop through each item in data
for (var i:int=0;i<resultAC.length;i++) {
//create person VO
var person:Person = new Person();
//add data
person.fill(resultAC[i]);
//add person to main data provider
peopleDataProvider.addItem(person);
}
}
}
ItemRenderer and Override of ’set data’
Next we’ll look at how the data is dealt with inside the ItemRenderer. The DataGrid’s only column is set to have an ItemRenderer. When the DataProvider is populated the DataGrid is going to set the ‘data’ property on each row’s ItemRenderer with the the associated VO in the DataProvider ArrayCollection. We want to make sure that the data inside the ItemRenderer is actually a Person VO object (not a generic Object), so we need to override the ’set data’ function. When we override this function we are now able to cast the data value as a Person VO. This will allow us to refer to data inside the ItemRenderer as that VO with known attributes rather than a generic Object that it would otherwise be:
[Bindable]private var person:Person;
override public function set data(value:Object):void {
super.data = value;
if (value is Person) {
person = Person(value);
}
}
When overriding the set data function make sure to remember set ’super.data=value’. The ItemRenderer still needs to know the value of the data otherwise it will be treated like an empty row in the DataGrid.
Swap ItemRenderer Images Based on Data
As a nice UI feature let’s display a male/female icon based on the person’s gender. This is easy to do, we know the data will be a Person VO. So we can have the Image component ask for the correct image based on the ‘person.gender’ value:
<mx:Image id="gender_img" source="{getGenderImg(person.gender)}"...
Since the person variable is Bindable if there is a change the ‘getGenderImg’ function will be asked to give the image its source:
private function getGenderImg(gender:String):Class {
if (gender == Person.GENDER_FEMALE) {
return imgUserFemale;
} else {
return imgUserMale;
}
}
Highlight Selected ItemRenderer
Next let’s add some nice functionality to make the ItemRenderer stand out a little more when it is selected. To do this we need to override another function. This time we’re going to override the updateDisplayList function, this will allow us to set some styles and graphical elements to the ItemRenderer is if is the selected itemRenderer. Using ‘ListBase’ we are able to find out if the ‘owner’ (the DataGrid) has this data selected:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(ListBase(owner).isItemSelected(data)) {
name_lbl.setStyle("styleName","pnameselected");
selected_img.visible = true;
} else {
name_lbl.setStyle("styleName","pname");
selected_img.visible = false;
}
}
Enable ItemRenderer to dispatch a remove person event
Lastly we’d like the trash can icon to remove a the person when clicked. There are other (maybe more preferable, but that’s for a different example) methods, but for this example let’s have the ItemRenderer dispatch an event and have a listener set to catch that event. On the click event of the trash can icon there is an event dispatched:
public static const DELETE_PERSON_EVENT:String = "deletePerson";
private function deleteClick_handler():void {
var dEvt:Event = new Event(DELETE_PERSON_EVENT,true);
this.dispatchEvent(dEvt);
}
This ‘deletePerson’ event is dispatched by the ItemRenderer and importantly has ‘bubbles’ set to true. This bubbling enables the parent component to simply add a listener for the event:
myDG.addEventListener(PersonItemRenderer.DELETE_PERSON_EVENT,deletePerson_handler);
private function deletePerson_handler(evt:Event):void {
if (myDG.selectedIndex != -1)
peopleDataProvider.removeItemAt(myDG.selectedIndex);
}
That’s it for this example. The next example will build on this but go the route of a dynamic ItemRenderer, while they a little bit more complicated can be very flexible allowing for dynamic properties to be set on the itemRenderers.
View the Example
