Datagrid item editors and dynamic behavior (part 1/3)

though a lot of validation functionality is available in mxml through validators, i’ve always found it curious that Datagrid seems to be a bit short-changed.

for example, in mxml, i can create a TextInput and give it the ability to accept ranges of numbers, through both the restrict property and assigning it a NumberValidator, but how do we do the same in a Datagrid cell?

further, what happens when we want to dynamically process cell contents based on other data in the same row?

Adobe has a primer here:
http://www.adobe.com/devnet/flex/quickstart/creating_item_editors/

… with help on creating different kinds of item editors. but whenever they give an example of a cell into which you’re meant to enter numbers, they use a NumericStepper. and that’s great, but maybe i don’t always want to use a NumericStepper in my interface. maybe i want to use a TextInput component, just like the rest of the cells. further, we still haven’t addressed the kinds of dynamic behavior i mentioned above.

so what’s the solution?
using the approach on that Adobe page called ‘Using a component as an item editor’, and by delving into a little bit of ActionScript, we can make ourselves a TextInput item editor that can do everything we need.

i’m dividing this topic into 3 posts so we can build to our eventual solution.

let’s take an example:

say you’re building an app for your local high school’s wrestling team. you’ve already written the part of the app to pre-register wrestlers and now you’re working on the screen for weigh-in at the meet.

when wrestlers pre-register, they enter their names and respective weight classes. on the day of the meet, you want your weigh-in screen to flag an error to the user that a wrestler is out of his weight class.

let’s take a first stab at some prototype code. here’s the mxml you’ve written for the weigh-in app (called wrestling.mxml):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" >
<mx:XMLList id="wrestlers" xmlns="">
<wrestler>
<name> Bob Smith </name>
<weightClass> A </weightClass>
<weight> </weight>
</wrestler>
<wrestler>
<name> Tim McLarry </name>
<weightClass> B </weightClass>
<weight> </weight>
</wrestler>
<wrestler>
<name> Joe Doug </name>
<weightClass> C </weightClass>
<weight> </weight>
</wrestler>
<wrestler>
<name> Larry McTim </name>
<weightClass> D </weightClass>
<weight> </weight>
</wrestler>
</mx:XMLList>
<mx:DataGrid id="weigh_in" editable="true" dataProvider="{wrestlers}" >
<mx:columns>
<mx:DataGridColumn id="wrestler_name" headerText="Name" editable="false" dataField="name" />
<mx:DataGridColumn id="weight_class" headerText="Class" editable="false" dataField="weightClass" />
<mx:DataGridColumn id="weight" headerText="Weight" editable="true" dataField="weight"
itemEditor="WeightEditor" editorDataField="data" />
</mx:columns>
</mx:DataGrid>
<mx:Form >
<mx:FormHeading label="Weight Classes" />
<mx:FormItem label="A" >
<mx:Label text="0-99 lbs." />
</mx:FormItem>
<mx:FormItem label="B" >
<mx:Label text="100-135 lbs." />
</mx:FormItem>
<mx:FormItem label="C" >
<mx:Label text="136-169 lbs." />
</mx:FormItem>
<mx:FormItem label="D" >
<mx:Label text="107-210 lbs." />
</mx:FormItem>
</mx:Form>
</mx:Application>

pretty straightfoward. we’ve got a Datagrid with 3 columns, some test XML to fill in the name and weight class, and a small form letting us know the weight class ranges (which i made up, and likely has no bearing on any realworld scenario).

we’ve also referenced a WeightEditor.mxml, which is this code:

<?xml version="1.0" encoding="utf-8"?>
<mx:TextInput restrict="1234567890,." xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ValidationResultEvent;
import mx.validators.NumberValidator;
/**
* This method is invoked when the user enters a value in the weight column
* of the weigh_in datagrid. We'll validate the user-entered value as a number
* and return a blank if it's not a number. Otherwise, we'll return what the
* user entered.
*/
override public function get data() : Object
{
var value:String = text;
if (!this.validate(value))
return '';
return value;
}
/**
* This is our validation method. We pass validation if the user has
* entered a non-negative decimal.
*
* @param value   The user-entered value
* @return true if we pass validation, false otherwise
*/
protected function validate(value:String) : Boolean
{
var validator:NumberValidator = new NumberValidator();
validator.allowNegative = false;
validator.required = false;
var result:ValidationResultEvent = validator.validate(value);
if (result.type != ValidationResultEvent.VALID)
return false;
return true;
}
]]>
</mx:Script>
</mx:TextInput>

this code is more interesting. first, note that we’ve derived this item editor from TextInput, so it should behave more like the other cells than, say, a NumericStepper would. second, you’ll notice that we set the restrict property straightaway, so we see an immediate benefit that the user can enter only numbers, periods and commas in this field.

we override the data method here to return what the user entered if it’s a number. if it’s not a number (e.g. 5.5.5..5), we’ll return nothing.

why is the method called ‘data’? because that’s the value we specified in the editorDataField in the weight column in the wrestling.mxml file. it doesn’t have to be called ‘data’, you can call it whatever you’d like. but because ‘data’ exists and is considered the default, we have to specify that we’re overriding it.

this is a decent first step, but doesn’t exhibit terribly useful behavior. first, if the user enters something that isn’t a number, the cell erases itself. good for avoiding keeping bad values around, not so good for the user experience. this is something we want to keep in mind for our next iteration.

also note that we haven’t honored, at all, the weight class. we’ll also fix this in a later iteration, and it would be nice if we could provide some meaningful user feedback for what went wrong.

we’ll address user notification in part 2.



(click on the image to run the app)

There are no comments.

Leave a Reply