Flex repeaters tutorial

Tagged:  

Flex Repeaters can save you a lot of time. As long as they work, but troubleshooting these little guys can be a serious pain in the butt. In this article I'm going to talk about some best practices to avoid some major headaches.

What is a repeater?
A Flex Repeater is basically a loop function in mxml. You give the repeater a data provider (A collection of data), and the repeater will iterate over that collection and display the MXML components within the repeater.

Simple example:

<VBox>
	<mx:Repeater id="schoolsRpt" dataProvider="{schoolsList}" recycleChildren="true">
		<mx:Text text="{School(schoolsRpt.currentItem).schoolName}"/>
	</mx:Repeater>
</VBox>

dataProvider. In this example, we are assuming we have some sort of collection with the name "schoolsList". This can be an an Array, an ArrayCollection, an ICollectionView, an IList, or an XMLList. The dataProvider isn't picky.

recycleChildren. This can cause problems. If you are experiencing buggy behavior; try changing this to false. Repeaters will automatically listen to changes in your dataProvider and update the repeated elements accordingly. Having recycleChildren be "true" can improve performance because after a data change, elements that haven't changed will not get re-created.

schoolsRpt.currentItem. This is the current item within the iteration. So if our dataProvider is an ArrayCollection of School objects, currentItem is the current School object.
There are two things to pay attention to about this. Firstly, since currentItem is just a generic Object, we want to cast it to what we know it to actually be. In my example we are doing that like so: School(schoolsRpt.currentItem). Secondly, currentItem is only available at the time of iteration. If you have an event handler, such as a click event. currentItem is no longer there, so you must use getRepeaterItem()
Example:

<VBox>
	<mx:Repeater id="schoolsRpt" dataProvider="{schoolsList}" recycleChildren="true">
		<mx:Button 
			text="{School(schoolsRpt.currentItem).schoolName}" 
			click="var btn:Button = Button(event.currentTarget); Alert.show(School(btn.getRepeaterItem()).schoolName + ' pressed')"/>
		/>
	</mx:Repeater>
</VBox>

VBox. You will notice that I surrounded my repeaters in VBox components. This is for two reasons. You will need a layout manager of some sort, otherwise your repeated components will all be on top of each other.

Another reason is because if you don't contain your repeater in some a container that doesn't have any other repeaters, you might get an error like this:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
	at mx.core::Repeater/getIndexForRepeater()
	at mx.core::Repeater/getIndexForFirstChild()
	at mx.core::Repeater/recreate()
	at mx.core::Repeater/execute()
	at mx.core::Repeater/collectionChangedHandler()

So keep all your repeaters in a unique container and you will hopefully never see that problem.

Hope this helps!

Hi,
I am having similar problem, when I have used data binding but the repeater does not repeat itself when the data source changes.
My Code::



width="100%" height="100%" name="xyz" showDataTips="true"
dataProvider="{model.simulation.getTenors(0,chartRepeater.currentItem.toString())}">








The Chart data was static initially and then when I added the function "executeBindings(true);", then, I saw the chage in my Charts. (when my dataSource was modifyied dynamically )
However, when I have my debuffer on the after the data has been loaded initially and when i change the datasource (selectedSectors), I can see the change in selectedSectors but the debugger never comes to the tag

In my output, my Chart data is displayed only for the modified datasource but for the rest, emplty charts are been seen.

Would appreciate any help :)
Thank you in advance

you should be aware that if you have more than one repeater in the first level of a container only the first will run. for example,
VBOX/
REPEATER id='repeater1'/
REPEATER id='repeater2'/
/VBOX

only repeater1 will execute. you can fix this by putting them in their own container
VBOX/
BOX/ REPEATER id='repeater1' /BOX
BOX/ REPEATER id='repeater2' /BOX
/VBOX

I am using a Grid container, inside it you can put GridRow containers, and inside those, GridItem containers.

I need to add different repeaters at GridRow level, so the repeaters put GridItem's in the GridRow

GRID/
GRIDROW/
REPEATER/ /GRIDITEM/ /REPEATER
REPEATER/ /GRIDITEM/ /REPEATER
/GRIDROW
/GRID

As GridRow does not accept any other element inside than GridItem, I can't nest repeaters inside any other container.

Can you give me any help?

All I can think of is to not use a repeater. Create invalidateGrid validateGrid methods and populate your grid manually.

Cool tip with making sure that each control should be placed into separate container to avoid RTE in function mx.core::Repeater/getIndexForRepeater()

Another workaround for this issue would be assigning dataProvider to mx:Repeater in ActionScript, instead of MXML binding, but in this case one has to make sure that we assign dataProviders to multiple mx:Repeaters in a presize order

Code sample

requestInstructionsList and linesList controls are both
---------------------------------
override protected function commitProperties() : void
{
super.commitProperties();
if (_linesChanged)
{
linesList.dataProvider = _lines;
_linesChanged = false;
}

if (_requestInstructionsChanged)
{
requestInstructionsList.dataProvider = _requestInstructions;
_requestInstructionsChanged = false;
}
}
---------------------------------

This tip was so helpful. It saved too much time and did exactly what i wanted. Thank you very much.