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.

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

Here's but I'd like to work;

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   
   <mx:DataGrid dataProvider="{products}" editable="true">
      <mx:columns>
         <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
         <mx:DataGridColumn width="60" headerText="Price" textAlign="right" dataField="price" editorDataField="text">
            <mx:itemEditor>
               <mx:Component>
                  <mx:NumericStepper xmlns:mx="http://www.adobe.com/2006/mxml" stepSize="0.01" minimum="0.01" maximum="100" />
               </mx:Component>
            </mx:itemEditor>
            <mx:itemRenderer>
               <mx:Component>
               <mx:HBox>   
                  <mx:CurrencyFormatter id="money" precision="2" />
                  <mx:Label id="price" text="{money.format(data.price)}" />
               </mx:HBox>
               </mx:Component>
            </mx:itemRenderer>
         </mx:DataGridColumn>
      </mx:columns>
   </mx:DataGrid>
   
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
         
         [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
      ]]>
   </mx:Script>
   
</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.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   
   <mx:DataGrid dataProvider="{products}" editable="true">
      <mx:columns>
         <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
         <mx:DataGridColumn width="60" headerText="Price" textAlign="right" editorDataField="value" dataField="price">
            <mx:itemEditor>
               <mx:Component>
                  <mx:NumericStepper xmlns:mx="http://www.adobe.com/2006/mxml" stepSize="0.01" minimum="0.01" maximum="100" />
               </mx:Component>
            </mx:itemEditor>
            <mx:itemRenderer>
               <mx:Component>
                  <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)}" />
               </mx:Component>
            </mx:itemRenderer>
         </mx:DataGridColumn>
      </mx:columns>
   </mx:DataGrid>
   
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
         
         [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
      ]]>
   </mx:Script>
   
</mx:Application>

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

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   
   <mx:DataGrid dataProvider="{products}" editable="true">
      <mx:columns>
         <mx:DataGridColumn width="100" headerText="Product" dataField="description" editable="false" />
         <mx:DataGridColumn width="60" headerText="Price" textAlign="right" dataField="price" editorDataField="value" itemRenderer="Money">
            <mx:itemEditor>
               <mx:Component>
                  <mx:NumericStepper xmlns:mx="http://www.adobe.com/2006/mxml" stepSize="0.01" minimum="0.01" maximum="100" />
               </mx:Component>
            </mx:itemEditor>         
         </mx:DataGridColumn>
      </mx:columns>
   </mx:DataGrid>
   
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
         
         [Bindable] private var products:ArrayCollection = new ArrayCollection([{description:"Milk", price:1.99}, {description:"Bread", price:1.50}, {description:"Honey", price:3.99}]);
      ]]>
   </mx:Script>
   
</mx:Application>

And the file Money.as:

package {
   import mx.controls.Text;
   import mx.formatters.CurrencyFormatter
   
   public class Money extends Text
   {
      override public function set data(value:Object):void {
         super.data = value;
         
         var cf:CurrencyFormatter = new CurrencyFormatter;
         cf.currencySymbol = "$";
         cf.precision = 2;
         
         if (value != null) {
            this.text = cf.format(value.price);
         }
         super.invalidateDisplayList();
      }
   }
}

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

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Seth Caldwell's Gravatar 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
Copyright © Justin Mclean 2008
BlogCFC by Raymond Camden.