Flex Numeric Stepper with Currency

Flex's numeric stepper controls work well but will only work with numeric data so can't be used for editing currency.

Update - for a better solution look at the last code section

There's a few ways around the issues but none of the solutions are perfect.

Here's but I'd like to work;

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
3
    
4    <mx:DataGrid dataProvider="{products}" editable="true">
5        <mx:columns>

6            <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
7            <mx:DataGridColumn width="60" headerText="Price" textAlign="right" dataField="price" editorDataField="text">
8                <mx:itemEditor>

9                    <mx:Component>

10                        <mx:NumericStepper stepSize="0.01" minimum="0.01" maximum="100" />
11                    </mx:Component>

12                </mx:itemEditor>

13                <mx:itemRenderer>

14                    <mx:Component>

15                    <mx:HBox>

16                        <mx:CurrencyFormatter id="money" precision="2" />
17                        <mx:Label id="price" text="{money.format(data.price)}" />
18                    </mx:HBox>

19                    </mx:Component>

20                </mx:itemRenderer>
21            </mx:DataGridColumn>
22        </mx:columns>
23    </mx:DataGrid>
24    
25    <mx:Script>
26        <![CDATA[
27            import mx.collections.ArrayCollection;
28            
29            [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"
Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
30        ]]>
31    </mx:Script>
32    
33</mx:Application>

But unfortunately it doesn't. The issue is that the numeric stepper is in a vbox and the datagrid can't get at it's value.

Here's an ugly solution. The + 0.05 are to deal with rounding errors that occur.

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
3
    
4    <mx:DataGrid dataProvider="{products}" editable="true">
5        <mx:columns>

6            <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
7            <mx:DataGridColumn width="60" headerText="Price" textAlign="right" editorDataField="value" dataField="price">
8                <mx:itemEditor>

9                    <mx:Component>

10                        <mx:NumericStepper stepSize="0.01" minimum="0.01" maximum="100" />
11                    </mx:Component>

12                </mx:itemEditor>

13                <mx:itemRenderer>

14                    <mx:Component>

15                        <mx:Label text="${Math.floor(data.price)}.{Math.floor((data.price-Math.floor(data.price))*10+0.05)}{Math.floor((data.price*10-Math.floor(data.price*10))*10+0.05)}" />
16                    </mx:Component>

17                </mx:itemRenderer>

18            </mx:DataGridColumn>
19        </mx:columns>
20    </mx:DataGrid>
21    
22    <mx:Script>
23        <![CDATA[
24            import mx.collections.ArrayCollection;
25            
26            [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"
Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
27        ]]>
28    </mx:Script>
29    
30</mx:Application>

Here's a better solution but it needs to use an actionscript component.

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
3
    
4    <mx:DataGrid dataProvider="{products}" editable="true">
5        <mx:columns>

6            <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
7            <mx:DataGridColumn width="60" headerText="Price" textAlign="right" dataField="price" editorDataField="value" itemRenderer="Money">
8                <mx:itemEditor>

9                    <mx:Component>

10                        <mx:NumericStepper stepSize="0.01" minimum="0.01" maximum="100" />
11                    </mx:Component>

12                </mx:itemEditor>

13            </mx:DataGridColumn>

14        </mx:columns>

15    </mx:DataGrid>

16    
17    <mx:Script>
18        <![CDATA[
19            import mx.collections.ArrayCollection;
20            
21            [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"
Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
22        ]]>
23    </mx:Script>
24    
25</mx:Application>

And the file Money.as:

view plain print about
1package {
2    import mx.controls.Text;
3    import mx.formatters.CurrencyFormatter
4    
5    public class Money extends Text
6    {
7        override public function set data(value:Object):void {
8            super.data = value;
9            
10            var cf:CurrencyFormatter = new CurrencyFormatter;
11            cf.currencySymbol = "$";
12            cf.precision = 2;
13            
14            if (value != null) {
15                this.text = cf.format(value.price);
16            }
17            super.invalidateDisplayList();
18        }
19    }
20}

While this works well there should be a more elegant solution. Anyone know how this can be done in a single MXML file?

Update

Here's a way to do it in a single MXML file.

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
3
    
4    <mx:CurrencyFormatter id="cf" precision="2" />
5    
6    <mx:DataGrid dataProvider="{products}" editable="true">
7        <mx:columns>

8            <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
9            <mx:DataGridColumn width="60" headerText="Price" textAlign="right" editorDataField="value" dataField="price">
10                <mx:itemEditor>

11                    <mx:Component>

12                        <mx:NumericStepper stepSize="0.01" minimum="0.01" maximum="100" />
13                    </mx:Component>

14                </mx:itemEditor>

15                <mx:itemRenderer>

16                    <mx:Component>

17                        <mx:Label text="{outerDocument.cf.format(data.price)}" />
18                    </mx:Component>

19                </mx:itemRenderer>

20            </mx:DataGridColumn>

21        </mx:columns>
22    </mx:DataGrid>
23    
24    <mx:Script>
25        <![CDATA[
26            import mx.collections.ArrayCollection;
27            
28            [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"
Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
29        ]]>
30    </mx:Script>
31    
32</mx:Application>

Related Blog Entries

TweetBacks
Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Single MXML file isn't needed, however, I re-implemented your solution slightly so that no actionscript in the mxml file is needed, and you simply use a reusable class.

Check it out - http://sethonflex.blogspot.com/2007/07/im-back-on-...
# Posted By Seth Caldwell | 7/27/07 10:52 AM
It can be done in a single MXML file by using outerDocument to reference a currency formatter.
# Posted By Justin Mclean | 5/18/09 6:18 PM