Friday, April 3, 2009

Changing the headers of dataGrid dynamically

In a recent project I was working on, I came across a situation where I will know the header text for the columns at run time, pulled from a xml document.

And here is how I did it.


private function setHeaderTexts():void {
var i:Number = 0;
var columns:ArrayCollection =new ArrayCollection(datagrid.columns);
for each (var column:DataGridColumn in columns) {
column.headerText = tempArrayCollection.getItemAt(i).toString();
//tempArrayCollection is where I store the list of headers from the XML
i++;
}
datagrid.invalidateDisplayList();
}


Hope it helps!

Bookmark and Share

Wednesday, April 1, 2009

Refresh tileList on DataChange

I happened to come across an issue with tileLists that use a custom itemRenderer.

The problem is that when I change the data provider, the items in the tileList do not redraw appropriately.

After some time spent in digging into this, I found out that for some reason the dataChange event in the itemrenderer is not triggered automatically when the data provider changes.

Note:DataChange event is triggered internally for dataGrids which are bound to a dataProvider, so we wont even notice it,but that is not the case for a tileList.

The event is triggered only when we call tileList.invalidateList().

So here is what I did. Call tileList.invalidateList() every time I change the dataProvider and handle the dataChange event in the itemRenderer and reset the UIControl's properties whatever it may be.

Here is what the view does.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;

[Bindable]
private var dataP:ArrayCollection = new ArrayCollection(
[{isMarried:true, isAnimal:true,name:"Montgomery"},
{isMarried:false, isAnimal:true,name:"Juneau"},
{isMarried:true, isAnimal:false,name:"Little Rock"},
{isMarried:true,isAnimal:true,name:"Ricky Martin"}]);

private function changeFirstElement():void {
dataP.getItemAt(0).name = "changed";
tileList.invalidateList();
}

]]>
</mx:Script>

<mx:TileList itemRenderer="testItemRenderer" dataProvider="{dataP}"
id="tileList"/>
<mx:Button label="change first element" click="changeFirstElement();"/>
</mx:Application>


And here is what the itemRenderere does.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" dataChange="handleDataChange()"
creationComplete="handleCreationComplete()">
<mx:Script>
<![CDATA[
[Bindable]
private var theName:String=new String();

private function handleCreationComplete():void {
if (data != null && data.hasOwnProperty("name")) {
theName =data.name;
}
}
private function handleDataChange():void {
if (data != null && data.hasOwnProperty("name")) {
if (theLabel) {
theName = data.name;
}
}
}
]]>
</mx:Script>
<mx:Label text="{theName}" id="theLabel"/>
</mx:Canvas>


Hope it helps!




Bookmark and Share

Reuse ItemRenderers for Multiple columns

When dealing with item renderers, one will come across all sorts of problems thrown at . One such case is "how to reuse the same itemrenderer"

Picture this case. You have a custom itemrenderer,( imagine a check box within a canvas for now) that performs a specific task and you want to reuse it on multiple columns. But how will the itemrenderer know which field in the arrayCollection is to be used to render itself appropriately?

Alright. Here is the trick.

There is this interface called IDropInListItemRenderer which your itemrenderer will have to implement to get access to listData which can be typeCasted to DataGridListData. The listData variable will hold reference to the owner of the itemRenderer and the hierarchy upwards. Following is the list of steps one has to follow.

1.Create the itemRenderer class that implements the IDropInListItemRenderer.

2.Create an instance variable to buffer the listData , namely _listData.

3.Override the set/get methods of the listData instance variable . In the setter, buffer the listData onto the instance variable

Ex:


private var _listData:DataGridListData;
public function set listData(value:BaseListData):void
{
_listData = DataGridListData(value);
}


Note:The importance of this step is that the itemrenderer can use the _listData variable to find out the name of the dataField , using something like _listData.dataField. Once the name of the dataField is acquire, the value for that datfield can be acquired by using data[_listData.dataField]

4.Override the updateDisplyList() method to update the status of the checkBox based on the value of the dataField.

Ex:

override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {

super.updateDisplayList(unscaledWidth,unscaledHeight);
_instanceCheckBox.selected = Boolean(data[_listData.dataField]);
}

5. Create the datagrid and use the above created item renderer.
Ex:

<mx:DataGridColumn dataField="isMarried" itemRenderer="sampleItemRenderer"/>
<mx:DataGridColumn dataField="isAnimal" itemRenderer="sampleItemRenderer" />




Following is the complete code.

The view:

// View
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var dataP:ArrayCollection = new ArrayCollection(
[{isMarried:true, isAnimal:true,name:"Montgomery"},
{isMarried:false, isAnimal:true,name:"Juneau"},
{isMarried:true, isAnimal:false,name:"Little Rock"},
{isMarried:true,isAnimal:true,name:"Ricky Martin"}]);
]]>
</mx:Script>



<mx:DataGrid dataProvider="{dataP}">
<mx:columns>
<mx:DataGridColumn dataField="isMarried" itemRenderer="sampleItemRenderer"/>
<mx:DataGridColumn dataField="isAnimal" itemRenderer="sampleItemRenderer" />
<mx:DataGridColumn dataField="name"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>



The itemRenderer


package
{
import mx.containers.Canvas;
import mx.controls.CheckBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;

public class sampleItemRenderer extends Canvas implements IDropInListItemRenderer
{
private var _listData:DataGridListData;
private var _instanceCheckBox:CheckBox = new CheckBox();
private var _currentDataFieldName:String = new String();
public function sampleItemRenderer()
{
super();
}

public function get listData():BaseListData
{
return _listData;
}

public function set listData(value:BaseListData):void
{
_listData = DataGridListData(value);
}
override protected function createChildren():void {
super.createChildren();
addChild(_instanceCheckBox);

}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth,unscaledHeight);
_instanceCheckBox.selected = Boolean(data[_listData.dataField]);
}
}
}

Hope it helps!



Bookmark and Share