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

14 comments:

lecochien said...

it's help me !
Thanks

G Naresh Kumar said...

Thanks a lot man! It helped..

cedric said...

Great Man ! Thanks a lot for sharing. I'll try to be as helpful as your are on the net.

Vengu said...

Glad to be of help , folks!

Zeleny said...

Helped a lot!!

André said...

Thanks bro! That helped me a lot!
I was having trouble with that... Then I changed it to yours. But I was having trouble again, because the TileList was not changing. Then I changed from the array.itemUpdated to array.setItemAt and it worked! Who knows... Thanks!

metric152 said...

I ran into a similar problem but wasn't able to solve it using your method. I did a write up of my solution. You can check it out here: http://blog.152.org/2009/11/flex-tilelist-cell-switching-problem.html

Sharath said...

Hey it helped me !
Thanks

Nils said...

Thanks a lot from me too!!!!! I had a similar problem and was diging in the code for hours until i found your blog article and was able to solve it!

prashant chaudhari said...

Hey Venkatesh,
Thanks for this help.But I am using a spark list (Flex 4) with tile layout and there is no invalidateList method on s:List.
What to do in such case?
Thanks in advance!

Anonymous said...

The complete example is so helpful!
I initially did not make var Bindable (in the example it's theName), but once I set it to be Bindable, it works. Can anyone explain why theName shall be Bindable?

George said...

Thanks so much for this example. You have explained it very nicely. Saved a lot of time for me. Thanks so much again.

vijay said...

Thanks man..!!! Its working..!!!

Ghelle said...

GREAT! Thanks!!!

Ill add something. It can ease a job for someone like you helped me. :)

for(var i:int = 0; i < SomeXML.xnode.length(); i++){
var tempObj:Object = new Object;
tempObj.label = SomeXML.xnode[i].@descr;
tempObj.source = new MovieClip();

myDataProvider.addItem(tempObj);
}

I add loaded image with addChild to myDataProvider:
myDataProvider.getItemAt(3).source.addChild(ImgLoader);