28
May
08

Displaying RadioButton controls using the Repeater in Flex (redux)

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.


12 Responses to “Displaying RadioButton controls using the Repeater in Flex (redux)”


  1. 1 Steve Walker May 29th, 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..

  2. 2 peterd May 29th, 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="NA" 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/.

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

    Thank you.

  4. 4 Steve Walker May 29th, 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?

  5. 5 peterd May 29th, 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

  6. 6 peterd May 29th, 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

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

    Once again, thank you.

  8. 8 MArcio Oct 27th, 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?

  9. 9 peterd Oct 27th, 2008 at 10:50 pm

    MArcio,

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

    Peter

  10. 10 David Nov 19th, 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>
    
  11. 11 Greg Feb 4th, 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

  12. 12 Andrew Mar 27th, 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.

Leave a Reply

This blog is terrible at eating HTML tags. If you plan on posting code/XML, please escape your "<" characters as "&lt;" and your ">" characters as "&gt;".




Badge Farm

  • Powered by Redoable 1.2
  • Cornify
  • Feeds burnt by Feedburner
  • Feed