You use the <mx:Repeater> tag to
declare a Repeater component that handles repetition of one or more
user interface components based on dynamic or static data arrays
at run time. The repeated components can be controls or containers.
Using a Repeater component requires data binding to allow for run-time-specific
values. For more information about data binding, see Storing data.
You can use the <mx:Repeater> tag anywhere
a control or container tag is allowed, as long as you wrap the repeater
tag in a MX container, such as VBox, HBox, Panel, or Canvas. If
you use a container such as Canvas that uses absolute positioning,
you must manually position each repeated element so that they do not
overlap.
To repeat user interface components, you place their tags within
the <mx:Repeater> tag. All components derived
from the UIComponent class can be repeated with the exception of
the Application container tag. Components that
are not based on UIComponent class cannot be children of the Repeater
control.
You can also use more than one <mx:Repeater> tag
in an MXML document, and you can nest <mx:Repeater> tags.
Declaring the Repeater component in MXML
You
declare the Repeater component in the <mx:Repeater> tag,
inside a MX container. The following table describes the Repeater
component’s properties:
Property
Description
id
Instance name of the corresponding Repeater
component.
dataProvider
An implementation of the ICollectionView
interface, IList interface, or Array class, such as an ArrayCollection object.
You
must specify a dataProvider value or the Repeater
component will not execute.
Generally, you specify the value
of the dataProvider property as a binding expression
because the value is not known until run time.
startingIndex
Number that specifies the element in the
data provider at which the repetition starts. The data provider
array is zero-based, so to start at the second element of the array,
specify a starting index of one. If the startingIndex is
not within the range of the dataProvider property,
no repetition occurs.
count
Number that specifies how many repetitions
occur. If the dataProvider property has fewer items
than the number in the count property, the repetition
stops with the last item.
currentIndex
Number that specifies the element of the dataProvider item
currently being processed. The data provider array is zero-based,
so when the third element is being processed, the current index
is two. This property changes as the Repeater component executes,
and is -1 after the execution is complete. It is a read-only property
that you cannot set in the <mx:Repeater> tag.
currentItem
Reference to the item that is being processed
in the dataProvider property. This property changes
as the Repeater component executes, and is null after the execution
is complete. It is a read-only property that you cannot set in the <mx:Repeater> tag.
After
a Repeater component finishes repeating, you do not use the currentItem property
to get the current item. Instead, you call the getRepeaterItem() method
of the repeated component itself. For more information, see Referencing repeated components.
recycleChildren
Boolean value that, when set to true,
binds new data items into existing Repeater children, incrementally
creates new children if there are more data items, and destroys
extra children that are no longer required. For more information,
see How a Repeater component executes.
The following table describes the Repeater component’s events:
Event
Description
repeat
Dispatched each time an item is processed
and currentIndex and currentItem are
updated.
repeatEnd
Dispatched after all the subcomponents of
a repeater are created.
repeatStart
Dispatched when Flex begins processing the dataProvider property
and begins creating the specified subcomponents.
Basic principles of the Repeater component
The simplest repeating
structures you can create with a Repeater component are static loops
that execute a set number of times. The following Repeater component
emulates a simple for loop that executes four times, printing a
simple line of text and incrementing the counter by one each time:
<?xml version="1.0"?>
<!-- repeater/StaticLoop.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns="*">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
[Bindable]
public var myArray:Array=[1,2,3,4];
]]>
</fx:Script>
<fx:Declarations>
<mx:ArrayCollection id="myAC" source="{myArray}"/>
</fx:Declarations>
<!-- Notice that the Repeater is inside a MX container. -->
<mx:VBox>
<mx:Repeater id="myrep" dataProvider="{myAC}">
<mx:Label id="Label1" text="This is loop #{myrep.currentItem}"/>
</mx:Repeater>
</mx:VBox>
</s:Application>
The executing SWF file for the previous example is shown below:
In actuality, the counter is
not the data within the array, but the position within the array.
As long as the array contains four elements, you can provide any
data within the array itself, and the Repeater component still executes
four times. The following example illustrates this principle:
<?xml version="1.0"?>
<!-- repeater/StaticLoop2.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
[Bindable]
public var myArray:Array=[10,20,30,40];
]]>
</fx:Script>
<fx:Declarations>
<mx:ArrayCollection id="myAC" source="{myArray}"/>
</fx:Declarations>
<!-- Notice that the Repeater is inside a MX container. -->
<mx:VBox>
<mx:Repeater id="myrep" dataProvider="{myAC}">
<mx:Label id="Label1" text="This is loop #{myrep.currentIndex+1}"/>
</mx:Repeater>
</mx:VBox>
</s:Application>
The executing SWF file for the previous example is shown below:
Notice that this example prints
the current index plus one, not the index itself. This is because
the first element of the array is assigned an index value of zero
(0).
You can also use the startingIndex and count properties
to adjust the starting point and total number of executions. The count property
sets a maximum on the number of times the Repeater component executes.
The count property is often—but not always—an exact
measure of the number of times that the content within the Repeater
component will execute. This number is because the Repeater component
stops after the last element of the data provider is reached, regardless
of the value of the count property.
The following
example shows how the count and startingIndex properties affect
a Repeater component:
The executing SWF file for the previous example is shown below:
The first Repeater component
loops through each element of the data provider, starting with the
first and stopping after the last. The second Repeater component
starts at the second element of the data provider and iterates four times,
ending at the fifth element. The third Repeater component starts
with the fourth element and continues until the end of the data
provider array, and then stops. Only three iterations occur despite
the fact that the count property is set to 6.
Creating dynamic loops with the Repeater component
Instead of a
static data written directly into your application, your application might
work with dynamic data providers. Dynamic data is defined in an <fx:Model> tag
and drawn from an XML file, a web service, a remote object, or some
other source. The data is collected and evaluated at run time to
determine the number and value of elements in the data provider
and how the Repeater component behaves.
In the following example,
an <mx:Repeater> tag repeats a RadioButton control
for each product in an XML file:
You can still use the count property
to restrict the number of iterations performed. You can use the startingIndex property
to skip entries at the beginning of the data provider.
In
the preceding example, the first product entry in the XML file contains metadata
that other applications use to create column headers. Because it doesn’t
make sense to include that entry in the radio buttons, start the
Repeater component at the second element of the data provider, as
in the following code example:
The executing SWF file for the previous example is shown below:
In this example, the id of the repeated Label
control is nameLabel; each nameLabel instance
created has this id. You reference the individual
Label instances as nameLabel[0], nameLabel[1],
and so on. You reference the total number of nameLabel instances
as nameLabel.length. The for loop traces
the text property of each Label control in the nameLabel Array
object. The labelTrace() method prints the name
and price of each product in the system log, provided you’ve defined
it in the mm.cfg file.
Referencing repeated child components
When a container is repeated
and indexed in an array, its children are also indexed. For example,
for the following MXML code, you reference the child Label controls
of the VBox container vb[0] as nameLabel[0] and shipLabel[0].
The syntax for referencing the children is the same as the syntax
for referencing the parent.
The executing SWF file for the previous example is shown below:
Referencing nested Repeater components
When <mx:Repeater> tags
are nested, the inner <mx:Repeater> tags
are indexed Repeater components. For example, for the following
MXML code, you access the nested Repeater components as r2[0], r2[1],
and so on. The syntax for referencing the children is same as the
syntax for referencing the parent.
The executing SWF file for the previous example is shown below:
This application places the
full list of products with color and price into the system log when
you click the Button control (provided you have defined the log file
in the mm.cfg file).
In the previous example, the instances
of the Label control are multiply indexed because they are inside
multiple Repeater components. For example, the index nameLabel[1][2] contains
a reference to the Label control produced by the second iteration
of r and the third iteration of r2.
Using the getRepeaterItem() method in an event handler for the Repeater component
When
a Repeater component is busy repeating, each repeated object that
it creates can bind at that moment to the Repeater component’s currentItem property,
which is changing as the Repeater component repeats. You cannot
give each instance its own event handler by writing something like click="doSomething({r.currentItem})" because
binding expressions are not allowed in event handlers, and all instances
of the repeated component must share the same event handler.
Repeated
components and repeated Repeater components have a getRepeaterItem() method
that returns the item in the dataProvider property
that was used to produce the object. When the Repeater component finishes
repeating, you can use the getRepeaterItem() method
to determine what the event handler should do based on the currentItem property.
To do so, you pass the event.currentTarget.getRepeaterItem() method
to the event handler. The getRepeaterItem() method
takes an optional index that specifies which Repeater components
you want when nested Repeater components are present; the 0 index
is the outermost Repeater component. If you do not specify the index
argument, the innermost Repeater component is implied.
Note: After a Repeater component finishes repeating,
you do not use the Repeater.currentItem property
to get the current item. Instead, you call the getRepeaterItem() method
of the repeated component itself.
The following example
illustrates the getRepeaterItem() method. When the
user clicks each repeated Button control, the corresponding colorName value
from the data model appears in the Button control label.
The executing SWF file for the previous example is shown below:
The code in the following example
uses the getRepeaterItem() method to display a
specific URL for each Button control that the user clicks. The Button controls
must share a common data-driven click handler, because you cannot use
binding expressions inside event handlers. However, the getRepeaterItem() method
lets you change the functionality for each Button control.
The executing SWF file for the previous example is shown below:
When executed, this example
yields two buttons: one for Flex and one for Adobe® Flash®. When you click the button of your choice,
the relevant product page loads in a new browser window.
Accessing specific instances of repeated components
Repeated components
and repeated Repeater components have three properties that you
can use to dynamically keep track of specific instances of repeated
objects, to determine which Repeater component produced them, and to
determine which dataProvider items were used by
each Repeater component. The following table describes these properties:
Property
Description
instanceIndices
Array that contains the indices required
to reference the component from its document. This Array is empty
unless the component is in one or more Repeater components. The
first element corresponds to the outermost Repeater component. For
example, if the id is b and instanceIndices is [2,4],
you would reference it on the document as b[2][4].
repeaters
Array that contains references to the Repeater
components that produced the component. The Array is empty unless
the component is in one or more Repeater components. The first element
corresponds to the outermost Repeater component.
repeaterIndices
Array that contains the indices of the items
in the dataProvider properties of the Repeater
components that produced the component. The Array is empty unless
the component is within one or more Repeater components. The first
element corresponds to the outermost Repeater component. For example,
if repeaterIndices is [2,4], the
outer Repeater component used its dataProvider[2] data
item and the inner Repeater component used its dataProvider[4] data
item.
This property differs from instanceIndices if
the startingIndex of any of the Repeater components
is not 0. For example, even if a Repeater component starts at dataProvider item
4, the document reference of the first repeated component is b[0],
not b[4].
The following example application uses
the repeaters property to display the id value
of the Repeater components in an Alert control when the user clicks
one of the Button controls labelled by the index value of the outer
Repeater component and inner Repeater component, respectively. It
uses the repeaters property to get the id value
of the inner Repeater component:
The executing SWF file for the previous example is shown below:
The following example application
uses the instanceIndices property to set the text property
of a TextInput control when the user clicks the corresponding Button
control in the set of repeated Button and TextInput controls. You
need to use the instanceIndices property because
you must get the correct object dynamically; you cannot get it by
its id value.
The following example shows
how to use the instanceIndices property to set
the text property of a TextInput control when the
user clicks a Button control. The argument event.target.instanceIndices gets
the index of the corresponding TextInput control.
The executing SWF file for the previous example is shown below:
The following code shows how
to use the repeaterIndices property instead of
the instanceIndices property to set the text property
of a TextInput control when the user clicks a Button control. The
value of event.target.repeaterIndices is based
on the current index of the Repeater component. Because the startingIndex property
of the Repeater component is set to 2, it does not match the event.target.instanceIndices value,
which always starts at 0.
The executing SWF file for the previous example is shown below:
In this case, clicking the
button prints the current element of the data provider, not the
current iteration of the loop.
Note: The value
of the repeaterIndices property is equal to the startingIndex property
on the first iteration of the Repeater component. Subtracting the startingIndex value
from the repeaterIndices value always yields the instanceIndices value.
Using a Repeater component in a custom MXML component
You can use the <mx:Repeater> tag
in an MXML component definition in the same way that you use it
in an application file. When you use the MXML component as a tag
in another MXML file, the repeated items appear. You can access
an individual repeated item by its array index number, just as you
do for a repeated item defined in the application file.
In the following example, a Button control in an MXML component
called childComp is repeated for every element
in an Array object called dp:
The application file in the following example uses the childComp
component to display four Button controls, one for each element
in the array. The getLabelRep() function displays
the label text of the second Button in the array.
The executing SWF file for the previous example is shown below:
Dynamically creating components based on data type
You can use a Repeater component to dynamically create
different types of components for specific items in a set of data.
A Repeater component broadcasts a repeat event
as it executes, and this event is broadcast after the currentIndex and currentItem properties
are set. You can call an event handler function on the repeat event,
and dynamically create different types of components based on the
individual data items.
How a Repeater component executes
A Repeater component executes initially when it is instantiated.
If the Repeater component’s dataProvider property
exists, it proceeds to instantiate its children, and they instantiate
their children, recursively.
The Repeater component re-executes whenever its dataProvider, startingIndex,
or count properties are set or modified either
explicitly in ActionScript, or implicitly by data binding. If the dataProvider property
is bound to a web service result, the Repeater component re-executes
when the web service operation returns the result. A Repeater component
also re-executes in response to paging through the dataProvider property
by incrementally increasing the startingIndex value,
as the following example shows:
r.startingIndex += r.count;
When a Repeater component re-executes, it destroys any children
that it previously created (assuming the recycleChildren property
is set to false), and then reinstantiates its children
based on the current dataProvider property. The
number of children in the container might change, and the container
layout changes to accommodate any changes to the number of children.
Recreating children in a Repeater component
The recycleChildren property
controls whether children of a Repeater component are recreated
when the Repeater component re-executes. When you set the recycleChildren property
to false, the Repeater component recreates all
the objects when you swap one dataProvider with
another, or sort, which causes a performance lag. Only set this
property to true if you are confident that modifying
your dataProvider will not recreate the Repeater component’s
children.
The default value of the recycleChildren property
is false, to ensure that you do not leave stale
state information in a repeated instance. For example, suppose you
use a Repeater component to display photo images, and each Image
control has an associated NumericStepper control for how many prints you
want to order. Some of the state information, the image, comes from
the dataProvider, while other state information,
the print count, is set by user interaction. If you set the recycleChildren property
to true and page through the photos by incrementally
increasing the Repeater component’s startingIndex value,
the Image controls bind to the new images, but the NumericStepper
controls keep the old information.