Tuesday, July 12, 2011

DataGroups in Flex: Part 3 - Creating custom itemRenderer

Today we will learn how to implement our own custom itemRenderer class.

When creating custom itemRenderers, the new custom class can either implement the IDataRenderer interface, or we can extend a class that already implements this interface, for example, DataRenderer. An interface is something that basically sets the standards of what the class should look like - what properties and methods it must have.

Here's the dataset that we are going to display in our DataGroup:

<fx:Declarations>
<mx:ArrayCollection id="myAC">
<fx:Object firstname="John" lastname="Jackson" age="25" />
<fx:Object firstname="Bob" lastname="Thompson" age="30" />
<fx:Object firstname="Andy" lastname="Doyle" age="30" />
</mx:ArrayCollection>
</fx:Declarations>

As you can see, its an array of Objects with multiple properties. All the properties are text values, so we are going to make a DataGroup that displays each element of the dataset as text.

Create a new mxml file in the same directory as your main mxml file. This will be our item renderer. Call it FullNameRenderer.mxml. Now the creation process is similar to creating a component. We know that we are only going to display text data, so let's make our renderer on a Label component's base.

<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx">

</s:Label>

We need to implement the IDataRenderer interface. This can be done by adding one more line to the code:

<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IDataRenderer">

</s:Label>

But we also needn't forget to import this class:

<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IDataRenderer">

<fx:Script>
<![CDATA[
import mx.core.IDataRenderer;
]]>
</fx:Script>

</s:Label>

Now, we must create the getter and setter functions, the ones that will be used by other objects to get and set the data of this object.

<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IDataRenderer">

<fx:Script>
<![CDATA[
import mx.core.IDataRenderer;
private var _data:Object;

public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
_data = value;
}
]]>
</fx:Script>

</s:Label>

Now, to set the text value of our Label, we can use the text property and assign it to the necessary property of the data object. Let's make it display the full name and age of the person:

<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IDataRenderer"
text="{data.firstname} {data.lastname} ({data.age})">

We're almost there. The last thing we need to do now - is to manage the data binding. The data only changes when the set data() method is called, so we can use that to dispatch an event, which we will listen to and update all the objects that are getting data from this object.

Let's dispatch an even in the setter:

public function set data(value:Object):void
{
_data = value;
dispatchEvent(new Event("dataChange"));
}

And add a binding tag that listens to this event before the getter:

[Bindable(event="dataChange")]
public function get data():Object
{
return _data;
}

So the full code of FullNameRenderer.mxml is:

<?xml version="1.0" encoding="utf-8"?>
<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx"
implements="mx.core.IDataRenderer"
text="{data.firstname} {data.lastname} ({data.age})">

<fx:Script>
<![CDATA[
import mx.core.IDataRenderer;
private var _data:Object;

[Bindable(event="dataChange")]
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
_data = value;
dispatchEvent(new Event("dataChange"));
}
]]>
</fx:Script>

</s:Label>

We can return to our main mxml file and set the itemRenderer propety of our DataGroup to FullNameRenderer.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
   width="120" height="120">
   
<fx:Declarations>
<mx:ArrayCollection id="myAC">
<fx:Object firstname="John" lastname="Jackson" age="25" />
<fx:Object firstname="Bob" lastname="Thompson" age="30" />
<fx:Object firstname="Andy" lastname="Doyle" age="30" />
</mx:ArrayCollection>
</fx:Declarations>


<s:DataGroup itemRenderer="FullNameRenderer" dataProvider="{myAC}">
<s:layout>
<s:VerticalLayout />
</s:layout>
</s:DataGroup>

</s:Application>

The results:

Thanks for reading!

Related:

DataGroups in Flex: Part 1 - Introduction, Using the List component
DataGroups in Flex: Part 2 - Creating a DataGroup
DataGroups in Flex: Part 4 - Virtualization

No comments:

Post a Comment