Displaying RadioButton controls using the Repeater in Flex (redux)

by Peter deHaan on May 28, 2008

in RadioButton, Repeater

In a previous example, “Displaying RadioButton controls using the Repeater in Flex”, we saw how you could use a Repeater in MXML to display a series of Flex RadioButton controls based on a data provider.

The following example shows how you can create a Repeater using ActionScript to accomplish the same thing.

Full code after the jump.

I’m not saying that creating a Repeater using ActionScript is the best/preferred/pretty way of doing this, but it is just one of many solutions.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/05/28/displaying-radiobutton-controls-using-the-repeater-in-flex-redux/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:comps="comps.*"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <comps:MyComp />

</mx:Application>

comps/MyComp.as

/**
 * http://blog.flexexamples.com/2008/05/28/displaying-radiobutton-controls-using-the-repeater-in-flex-redux/
 */
package comps {
    import flash.events.Event;

    import mx.containers.ApplicationControlBar;
    import mx.containers.Canvas;
    import mx.containers.Form;
    import mx.containers.FormItem;
    import mx.containers.HBox;
    import mx.controls.Alert;
    import mx.controls.Label;
    import mx.controls.RadioButton;
    import mx.controls.RadioButtonGroup;
    import mx.core.Application;
    import mx.core.Repeater;
    import mx.core.UIComponentDescriptor;
    import mx.styles.CSSStyleDeclaration;
    import mx.styles.StyleManager;

    public class MyComp extends Canvas {
        private var arr:Array;
        private var appControlBar:ApplicationControlBar;
        private var form:Form;
        private var formItem:FormItem;
        private var lbl:Label;
        private var hBox:HBox;
        private var radioGroup:RadioButtonGroup;
        private var radioRepeater:Repeater;

        public function MyComp() {
            super();
            init();
        }

        private function init():void {
            var alertCSS:CSSStyleDeclaration;
            alertCSS = StyleManager.getStyleDeclaration("Alert");
            alertCSS.setStyle("backgroundAlpha", 0.8);
            alertCSS.setStyle("backgroundColor", "black");
            alertCSS.setStyle("borderAlpha", 0.8);
            alertCSS.setStyle("borderColor", "black");

            arr = [];
            arr.push({label:"Red", data:"red"});
            arr.push({label:"Orange", data:"haloOrange"});
            arr.push({label:"Yellow", data:"yellow"});
            arr.push({label:"Green", data:"haloGreen"});
            arr.push({label:"Blue", data:"haloBlue"});

            radioGroup = new RadioButtonGroup();

            lbl = new Label();

            formItem = new FormItem();
            formItem.label = "selectedValue:";
            formItem.addChild(lbl);

            form = new Form();
            form.styleName = "plain";
            form.addChild(formItem);

            appControlBar = new ApplicationControlBar();
            appControlBar.dock = true;
            appControlBar.addChild(form);
            Application.application.addChildAt(appControlBar, 0);

            hBox = new HBox();
            hBox.setStyle("horizontalGap", 60);
            addChild(hBox);

            var descriptorProps:Object = {};
            descriptorProps.type = RadioButton;
            descriptorProps.document = this;
            descriptorProps.propertiesFactory = radioPropFac;
            descriptorProps.events = {change:"radioButton_change"};

            var radioDescriptor:UIComponentDescriptor = new UIComponentDescriptor(descriptorProps);

            radioRepeater = new Repeater();
            radioRepeater.dataProvider = arr;
            radioRepeater.childDescriptors = [radioDescriptor];
            radioRepeater.initializeRepeater(hBox, true);
        }

        private function radioPropFac():Object {
            var obj:Object = {};
            obj.label = radioRepeater.currentItem.label;
            obj.group = radioGroup;
            return obj;
        }

        public function radioButton_change(evt:Event):void {
            var radio:RadioButton = RadioButton(evt.currentTarget);
            var item:Object = radio.getRepeaterItem();
            var cssObj:CSSStyleDeclaration;
            cssObj = StyleManager.getStyleDeclaration("Alert");
            cssObj.setStyle("modalTransparencyColor", item.data);
            cssObj.setStyle("themeColor", item.data);
            Alert.show(item.label, "getRepeaterItem()");

            callLater(updateSelectedValue, [evt]);
        }

        private function updateSelectedValue(evt:Event):void {
            lbl.text = radioGroup.selectedValue.toString();
        }
    }
}

View source is enabled in the following example.

{ 15 comments… read them below or add one }

1 Steve Walker May 29, 2008 at 4:59 am

Completely unrelated to this post, but desperately needed. How can I build an item renderer for a dataGrid that evaluates a text string in a cell and changes the background color. If it is blank/null/undefined make it red, if else it has the text N/A, NA, or N\A make it amber, etc..

Reply

2 peterd May 29, 2008 at 8:18 am

Steve Walker,

Perhaps a little crude, but this should work:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Array id="arr">
        <mx:Object label="San Francisco" population="776733" year="2000" />
        <mx:Object label="San Jose" population="894943" year="2000" />
        <mx:Object label="San Mateo" population="92482" year="2000" />
        <mx:Object label="Daly City" year="2000" />
        <mx:Object label="Pacifica" population="N/A" year="2000" />
        <mx:Object label="Foster City" population="NA" year="2000" />
        <mx:Object label="Redwood City" population="N\A" year="2000" />
        <mx:Object label="Fremont" population="" year="2000" />
    </mx:Array>

    <mx:DataGrid id="dataGrid" dataProvider="{arr}">
        <mx:columns>
            <mx:DataGridColumn dataField="label" />
            <mx:DataGridColumn dataField="year" />
            <mx:DataGridColumn dataField="population"
                    itemRenderer="comps.CustomItemRenderer" />
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

comps/CustomItemRenderer.as:

package comps {
    import mx.controls.dataGridClasses.DataGridItemRenderer;

    public class CustomItemRenderer extends DataGridItemRenderer {

        override public function validateNow():void {
            super.validateNow();
            if (data) {
                switch(data.population) {
                    case undefined:
                    case null:
                        data.population = "";
                    case "":
                        background = true;
                        backgroundColor = 0xFF0000;
                        break;
                    case "N/A":
                    case "N\\A":
                    case "NA":
                        background = true;
                        backgroundColor = 0xFFFF00;
                        break;
                    default:
                        background = false;
                        backgroundColor = 0xFFFFFF;
                        break;
                }
            }
        }
    }
}

Peter

For more great posts on item renderers, check out Alex Harui’s blog at http://blogs.adobe.com/aharui/, and more specifically, http://blogs.adobe.com/aharui/item_renderers/.

Reply

3 Steve Walker May 29, 2008 at 11:23 am

Thank you.

Reply

4 Steve Walker May 29, 2008 at 4:58 pm

I combined the example you placed above with the one from the site you referenced and it works like a charm. I really appreciate all your assistance. I have one more problem related to this and it is how to use a wildcard in the evaluation of the string. Thanks to the ingenuity of lazy people, the data that I have has 30 or more variations of UNKNOWN (e.g. UNK, UNK101, UNK2, UNKOWN, etc) and I would like the renderer to match anything that starts with UNK. Is it possible?

Reply

5 peterd May 29, 2008 at 6:06 pm

Steve Walker,

Not sure if this would work with the switch statement, but it may give you a starting point:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Array id="arr">
        <mx:Object label="UNKNOWN" />
        <mx:Object label="UNK" />
        <mx:Object label="UnK101" />
        <mx:Object label="Porridge" />
        <mx:Object label="UNK2" />
        <mx:Object label="Pineapples" />
    </mx:Array>

    <mx:Script>
        <![CDATA[
            import mx.controls.dataGridClasses.DataGridColumn;

            private function isUnknown(value:String):Boolean {
                return value.search(/UNK/i) == 0;
            }

            private function labelFunc(item:Object, col:DataGridColumn):String {
                if (isUnknown(item.label)) {
                    return "yes";
                } else {
                    return "no";
                }
            }
        ]]>
    </mx:Script>

    <mx:DataGrid id="dataGrid" dataProvider="{arr}">
        <mx:columns>
            <mx:DataGridColumn dataField="label"
                    headerText="label:" />
            <mx:DataGridColumn labelFunction="labelFunc"
                    headerText="UNKNOWN:" />
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

Peter

Reply

6 peterd May 29, 2008 at 6:12 pm

You could also do something like the following (using the indexOf() instead of the search() method):

private function isUnknown(value:String):Boolean {
    return value.indexOf("UNK") == 0;
}

Although the indexOf() method would perform a case sensitive search instead of our clever case insensitive search using the search() method.

Peter

Reply

7 Steve Walker May 30, 2008 at 7:06 am

Once again, thank you.

Reply

8 MArcio October 27, 2008 at 2:51 pm

How do Repeater in ActionScript?

I am using this way!

But only runs the first record!

private function Repeat (): void (

var repeater: Repeater = new Repeater ();
repeater.dataProvider = dataprovider_Controller.item;

trace ( "repeater.currentItem.image:" + repeater.currentItem.image);
var image: Image = new Image ();

image.setStyle ( "HorizontalAlign", "left");
image.source = repeater.currentItem.image;
image.id = "image";
trace ( "image.source:" + image.source);

)

I think I have to quit Repeat to make the loop of
records, but how would this in ActionScript?

Reply

9 peterd October 27, 2008 at 10:50 pm

MArcio,

The example at the top of the page shows how to create a Repeater using ActionScript.

Peter

Reply

10 David November 19, 2008 at 2:21 pm

I have a complicated problem using a Repeater.
There are four new classes: Souce, SourceData, Tactic, TacticData.
Source has a name.
SourceData has a Source (thus a Source name) and quantity.
Tactic has a name.
TacticData has a Tactic (…), selected, dueDate, and done.
(Nevermind why it has to be so split up like that.)
When displayed, a Source has one or more Tactics.
If a tactic is selected, then dueDate and done are enabled.
Now the problems:
1- I’ve gotten this much to for the data supplied at compile time, but how to make the tactic’s field change at runtime?
2- Bonus: if a tactic’s done is checked, then the entire tactic is disabled (selected and dueDate) except done. And then, another tactic of the same name must appear in the same source.
I don’t know if that makes any sense the way I explain it, but here is the source and if I could just get the first problem solved, I’ll be doing alright:
Source.as:

package
{
	public class Source
	{
		public function Source(){}

		public function get name():String {
			return _name;
		}
		public function set name(value:String):void{
			_name = value;
		}
		private var _name:String = "";
	}
}

SourceData.as:

package
{
	public class SourceData
	{
		public function SourceData(source:Source) {
			_source = source;
		}

		public function name():String {
			return _source.name;
		}
		public function get quantity():Number {
			return _quantity;
		}
		public function set	quantity(value:Number):void {
			_quantity = value;
		}
		private var _source:Source = null;
		private var _quantity:Number = 0;
	}
}

Tactic.as:

package
{
	public class Tactic
	{
		public function Tactic(){}

		public function get name():String {
			return _name;
		}
		public function set name(value:String):void{
			_name = value;
		}
		private var _name:String = "";
	}
}

TacticData.as:

package
{
	public class TacticData
	{
		public function TacticData(tactic:Tactic){
			_tactic = tactic;
		}
		//this must be a get (unlike the name function of SourceData)
		//for the label of checkboxes
		//either that or jump thru some hoops when calling name to display text of function result
		public function get name():String {
			return _tactic.name;
		}
		public function get selected():Boolean {
			return _selected;
		}
		public function set selected(value:Boolean):void{
			_selected = value;
		}
		public function get dueDate():Date {
			return _dueDate;
		}
		public function set dueDate(value:Date):void{
			_dueDate = value;
		}
		public function get done():Boolean {
			return _done;
		}
		public function set done(value:Boolean):void{
			_done = value;
		}
		private var _selected:Boolean = false;
		private var _dueDate:Date = new Date();
		private var _done:Boolean = false;
		private var _tactic:Tactic = null;
	}
}

Main.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
	creationComplete="init()">
<mx:Script>
<![CDATA[
	import mx.controls.CheckBox;
	import mx.controls.Alert;
	import mx.collections.ArrayCollection;

	[Bindable]
	private var sources:ArrayCollection;

	private function init():void{
			var s1:Source = new Source();
			s1.name = "Source 1"
			var s2:Source = new Source();
			s2.name = "Source 2"

			var s1d:SourceData = new SourceData(s1);
			var s2d:SourceData = new SourceData(s2);

			var ta:Tactic = new Tactic();
			ta.name = "tactic A";
			var tb:Tactic = new Tactic();
			tb.name = "tactic B";
			var tc:Tactic = new Tactic();
			tc.name = "tactic C";

			var tad:TacticData = new TacticData(ta);
			var tbd:TacticData = new TacticData(tb);
			tbd.selected=true;
			var tcd:TacticData = new TacticData(tc);

			var a1:Array = new Array(tad,tbd);
			var a2:Array = new Array(tcd);

			sources = new ArrayCollection();
			sources.addItem({name:s1d.name(),quantity:s1d.quantity,tactics:a1});
			sources.addItem({name:s2d.name(),quantity:s2d.quantity,tactics:a2});
	}
	private function checkTactic(event:Event):void{
		var cb:CheckBox = event.currentTarget as CheckBox;
		var t:TacticData = cb.getRepeaterItem() as TacticData;
	}
	private function checkDone(event:Event):void{
		var cb:CheckBox = event.currentTarget as CheckBox;
		var t:TacticData = cb.getRepeaterItem() as TacticData;
		//Alert.show(t.name);
		//now how to get the sourceData associated with this tacticData?
	}
	private function n():void{
		var a:int = 0;
		a++;
	}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%">
	<mx:HBox horizontalGap="0" >
		<mx:Label text="Source" fontSize="14" fontWeight="bold" />
		<mx:Label text="Quantity" fontSize="14" fontWeight="bold" />
		<mx:Label text="Tactic" fontSize="14" fontWeight="bold" />
	</mx:HBox>

	<mx:Grid horizontalScrollPolicy="auto" verticalScrollPolicy="auto"
		id="mainGrid"
		width="100%" >
		<mx:Repeater id="repSources" dataProvider="{this.sources}"
			>
			<mx:GridRow>
				<mx:GridItem colSpan="2">
					<mx:HRule width="100%" />
				</mx:GridItem>
			</mx:GridRow>
			<mx:GridRow>
				<mx:GridItem>
					<mx:Label id="sourceName" text="{repSources.currentItem.name}" />
				</mx:GridItem>
				<mx:GridItem>
					<mx:TextInput text="{repSources.currentItem.quantity}" />
				</mx:GridItem>
				<mx:GridItem>
				<mx:VBox>
					<mx:Repeater id="repTactics" dataProvider="{repSources.currentItem.tactics}">
					<mx:HBox>
						<mx:CheckBox label="{repTactics.currentItem.name}"
							selected="{repTactics.currentItem.selected}"
							change="checkTactic(event)"/>
						<mx:DateField enabled="{repTactics.currentItem.selected}"/>
						<mx:CheckBox label="Done"
							selected="{repTactics.currentItem.done}"
							enabled="{repTactics.currentItem.selected}"
							change="checkDone(event)"/>
					</mx:HBox>
					</mx:Repeater>
				</mx:VBox>
				</mx:GridItem>
			</mx:GridRow>
		</mx:Repeater>
	</mx:Grid>
</mx:VBox>

</mx:Application>

Reply

11 Greg February 4, 2009 at 11:56 pm

From the example above, suppose you had two items you wanted repeated and you want both of those items wrapped in an HBox. I modified the code to include a new UIComponentDescriptor for a TextInput field. How can you put the two UIComponentDescriptor’s in a HBox and tell the repeater to repeat those objects into a Tile.

Do I create another UIComponentDescriptor for the HBox or do a var myHbox:HBox = new HBox()? And then how do I put the Radio button and TextInput into myHbox and get the repeater to repeat that entire process?

radioRepeater = new Repeater();
radioRepeater.dataProvider = arr;
radioRepeater.childDescriptors = [radioDescriptor, txtInputDescriptor];
radioRepeater.initializeRepeater(myTile, true);

All the things I’ve tried only scattered my objects all over the screen or I had one Huge long horizontal box that scrolled off the screen.

Thanks
Greg

Reply

12 Andrew March 27, 2009 at 11:28 am

This was a great example. I’m using the same logic but I’m using the repeater for the text component. For reasons I won’t get into, I was having problems with the line:
descriptorProps.propertiesFactory = radioPropFac;

I decided to replace the function “radioPropFac” with the something like this:

descriptorProps.propertiesFactory = function():Object {
return {
text: itemRepeater.currentItem.label
}}

…that worked like a charm.

Reply

13 Rodrigo September 15, 2009 at 7:05 pm

Hello friend

Excellent article, I’m trying to do something close to this, but I’m having trouble, I wonder if I can help, here’s what I’m doing:
I built a panel only via code and put it in a Canvas also via code and then a vbox and finally put a Canvas (which I want to repeat), I sought data from a php file, but so far I could not do repeat, here’s the code:

import mx.core.UIComponentDescriptor;
import mx.controls.Text;
import mx.controls.Image;
import mx.controls.Label;
import mx.managers.PopUpManager;
import mx.containers.Panel;
import mx.core.Repeater;
import mx.containers.Canvas;
import mx.containers.VBox;
import mx.controls.Label;
public var canvas:Canvas;
public var vbox:VBox;
public var rep:Repeater;
public var win:Panel;
public var msgErr:Text;
public var imgClose:Image;
public var title:Label;

public function winFiles(evt:Event):void {
param = new Text();
param.text = evt.currentTarget.automationName;
recFiles.send();
}

{ param.text}

private function checkFiles(evt:ResultEvent):void {
win = new Panel();
imgClose = new Image();

imgClose.source = “../images/close.png”;
imgClose.scaleContent = true;
imgClose.autoLoad = true;
imgClose.toolTip = “FECHAR”;
imgClose.setStyle(“right”,”5″);
imgClose.setStyle(“top”,”5″);
imgClose.y = 50;
imgClose.buttonMode = true;
if(evt.result.dados.registros == “0″) {
msgErr = new Text();
win.width = 380;
win.height = 355;
win.title = “:: Anexos (“+evt.result.dados.registros+”)”;
win.x = (Application.application.width – win.width) / 2;
win.y = (Application.application.height – win.height) / 2;
win.layout = “absolute”;

msgErr.text = “no file found”;
msgErr.setStyle(“left”,”5″);
msgErr.setStyle(“top”,”5″);
msgErr.width = 180;
msgErr.height = 50;

win.addChild(msgErr);
PopUpManager.addPopUp(win,panel1,true);
} else {
canvas = new Canvas();
rep = new Repeater();
vbox = new VBox();

var canvBox:Canvas = new Canvas();
var lblname:Label = new Label();
var name:Label = new Label();
var date:Label = new Label();
var hour:Label = new Label();

win.width = 380;
win.height = 355;
win.title = “:: Anexos (“+evt.result.dados.registros+”)”;
win.x = (Application.application.width – win.width) / 2;
win.y = (Application.application.height – win.height) / 2;
win.layout = “absolute”;

canvas.width = 355;
canvas.height= 260;
canvas.setStyle(“left”,”0″);
canvas.setStyle(“top”,”50″);

vbox.setStyle(“left”,”5″);
vbox.setStyle(“top”,”0″);
vbox.setStyle(“verticalGap”,”6″);
vbox.width = 335;
vbox.height = 260;

canvas.addChild(vbox);

canvBox.width = 320;
canvBox.height= 60;
canvBox.setStyle(“backgroundColor”,”#ededed”);
canvBox.setStyle(“borderStyle”,”solid”);
canvBox.setStyle(“cornerRadius”,”5″);

vbox.addChild

var repAnexos:UIComponentDescriptor = new UIComponentDescriptor(canvBox);

rep.dateProvider = recAnexos.lastResult.anexos;
rep.childDescriptors = [repAnexos];
rep.initializeRepeater(vbox, true);

vbox.addChild(rep);

lblname.text = “Name:”;
lblname.setStyle(“fontWeight”,”bold”);
lblname.setStyle(“left”,”0″);
lblname.setStyle(“top”,”5″);
lblname.width = 100;

name.setStyle(“left”,”110″);
name.setStyle(“top”,”5″);
name.width = 100;

canvBox.addChild(lblname);
canvBox.addChild(name);
win.addChild(canvas);
PopUpManager.addPopUp(win,panel1,true);
}
win.addChild(imgClose);
imgClose.addEventListener(MouseEvent.CLICK, closeFiles);
}
private function closeFiles(evt:Event):void {
PopUpManager.removePopUp(win);
}

Reply

14 Anonymous November 11, 2009 at 8:31 pm

, i want to do it the above mxml in as3… anyone help me.. i cannt repeat the datas in repeater while using in as3

box_v=new VBox();
babyactimg=new Image();
rep=new Repeater();
addChild(box_v);
rep.dataProvider=cat.img;
babyactimg.source=rep.currentItem.@src;
babyactimg.width=30;
babyactimg.height=30;
addChild(babyactimg);
box_v.addChild(rep);
this was i done in as3 but i got the first record only…what can i do for get all the records from the repeater using as3..

Reply

15 Jamie February 5, 2010 at 2:13 pm

Hey Peter, this is the exact solution I needed for a component in my current project. I’m using the exact same method as demonstrated in your example but I’m having one problem that I cannot seem to solve. After the initial creation of the Repeater and its children, the parent and parentDocument property on the Repeater itself as well as it’s children is null. When I try and remove an item from the dataProvider the framework throws an RTE because it needs those properties to update the Repeater’s display list. Any insight into what I may be doing wrong?

Thanks,
Jamie

Reply

Leave a Comment

Sorry, this blog is terrible at eating HTML comments.
If you're pasting any HTML/XML/MXML code, you need to convert your < characters to &lt; and your > characters to &gt; .

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: