itemEditors – Part 1

inline itemEditors

I recently completed a series on itemRenderers – customizations to list controls which format the display of the list contents. Displaying and rendering content is very cool and with Flex you can do nearly anything you can imagine.

This new series covers itemEditors – a way to allow data to be changed directly inside of a list control. This first article covers inline itemEditors which are very simple, though quite useful, components you write directly inside your MXML files. The other articles in the series will cover more complex editing, validation, events, and using itemRenderers as itemEditors.

The source code to this article is available by downloading it here.

TextInput Editor

It is nice to edit directly in the list controls. You can imagine a DataGrid of warehouse inventory where you can adjust the content right in the grid without needing a special pop-up. The list controls have a built in editor – a TextInput control – which appears whenever the user clicks the mouse in an editable area, either a row (for a List), a branch (for a Tree), or a cell (for a DataGrid). All you need to do is set the list control’s editable property to true. For a DataGrid you can exclude a column from being edited by setting the DataGridColumn’s editable property to false.

Before editing a cell
After clicking on a cell, the editor opens and the content is ready for editing.

itemEditors differ from itemRenderers in that only one instance of the itemEditor is seen – just on the cell being edited. The itemEditor is not seen until the cell to be edited receives input focus. Then the itemRenderer is hidden and the itemEditor is moved to that position, sized to fit the area, and given the data for the record. When editing is finished (by moving focus to another location), the list control copies the new value from the editor to the dataProvider record.

Using the image above as an example, when the user clicks in a cell of the "Part #" column, the dataProvider[row][dataField] value is given to the text property of the itemEditor (TextInput) control. When editing is finished, the text property value from the itemEditor (TextInput) control is copied to the dataProvider[row][dataField]. The dataProvider, being a collection, dispatches an event in response to the update.

While the default TextInput control makes a fine editor, it really only works for the most simple of cases. It works fine for String values, for example, such as a book title, author name, or product number. If you need more control or want to validate the user’s input, then you need to take matter into your own hands.

Flex Controls as itemEditors

Here is how you make an itemEditor which only accepts numeric values:

	<mx:DataGrid x="46" y="270" editable="true" dataProvider="{employeeDB}">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="name"/>
<mx:DataGridColumn headerText="Position" dataField="position"/>
<mx:DataGridColumn headerText="Age" dataField="age">
	<mx:itemEditor>
<mx:Component>
<mx:TextInput restrict="0-9" maxChars="3" />
</mx:Component>
</mx:itemEditor> 
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

A very common control to use for an itemEditor is the CheckBox. This is very useful for editing Boolean values. Here is an example of using the CheckBox to edit the values for an "In Stock" column of an inventory program:

<mx:DataGrid x="531" y="273" editable="true" dataProvider="{inventoryDB}">
<mx:columns>
<mx:DataGridColumn headerText="Product" dataField="product"/>
<mx:DataGridColumn headerText="Part #" dataField="part"/>
	<mx:DataGridColumn headerText="In Stock?" dataField="inStock"
labelFunction="inStockLabeler"
itemEditor="mx.controls.CheckBox" editorDataField="selected" /> 
<mx:DataGridColumn headerText="Quantity" dataField="quantity"/>
</mx:columns>
</mx:DataGrid>

In this example the content of the cells in this column are rendered using a labelFunction (inStockLabeler) which could display anything such as "Yes", "No", "In Stock", or "Out of Stock". The itemEditor property is set to the mx.controls.CheckBox class. And there is another, equally important, property set on the DataGridColumn: editorDataField. This field indicates the property of the itemEditor class to use to fetch the value when editing is finished. In this case it is the CheckBox’s selected property. When editing is finished, the DataGrid will use the CheckBox’s selected property to replace the inStock property in the data record.

You may wonder why the example with the TextInput did not supply the editorDataField property. That is because the default value for editorDataField is "text" which just happens to be name of the property on the TextInput control holding the value.

You can use this same technique with a number of Flex controls. Here is one for an order quantity column using NumericStepper:

	<mx:DataGrid x="531" y="82" editable="true" dataProvider="{inventoryDB}">
<mx:columns>
<mx:DataGridColumn headerText="Product" dataField="product"/>
<mx:DataGridColumn headerText="Part #" dataField="part"/>
<mx:DataGridColumn headerText="In Stock?" dataField="inStock"/>
	<mx:DataGridColumn headerText="Quantity" dataField="quantity"
itemEditor="mx.controls.NumericStepper" editorDataField="value"/> 
</mx:columns>
</mx:DataGrid>

Notice the editorDataField is "value" – the property of the NumericStepper which holds the current value of the control. Make sure you use the fully-qualified class name for the itemEditor property.

Complex Editor

Now suppose you want to do something a little more complex that doesn’t have a ready-made Flex control available. Here is one which allows a credit card number to be entered using 4 separate 4-digit fields:

	<mx:DataGrid x="46" y="463" editable="true" dataProvider="{accountDB}" width="302">
<mx:columns>
<mx:DataGridColumn headerText="Account" dataField="account" width="100"/>
<mx:DataGridColumn headerText="Credit Card" dataField="ccard" editorDataField="value">
<mx:itemEditor>
<mx:Component>
<mx:HBox>
<mx:Script>
<![CDATA[
public function get value() : String
{
return part1.text+part2.text+part3.text+part4.text;
}
override public function set data(value:Object):void
{
super.data = value;
part1.text = value.ccard.substr(0,4);
part2.text = value.ccard.substr(4,4);
part3.text = value.ccard.substr(8,4);
part4.text = value.ccard.substr(12,4);
}
]]>
</mx:Script>
<mx:TextInput id="part1" maxChars="4" restrict="[0-9]" width="40" />
<mx:TextInput id="part2" maxChars="4" restrict="[0-9]" width="40" />
<mx:TextInput id="part3" maxChars="4" restrict="[0-9]" width="40" />
<mx:TextInput id="part4" maxChars="4" restrict="[0-9]" width="40" />
</mx:HBox>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

This inline itemEditor follows the same rules as other itemEditors and names the editorDataField as "value". The component chosen for the itemEditor is the HBox – which does not have a "value" property. To make this itemEditor work, a getter function named value is created to return the concatenation of the 4 input fields. Now when editing for the cell completes, the DataGrid can call upon the value property of the itemEditor and it will receive the combined fields.

You can also see that I have overridden the data setter function. In that function I split up the credit card number among the four TextInput fields. This is the technique you use to display the data to be edited. The editorDataField is the property used to retrieve the new value.

Conclusion

In this article you’ve seen how to create an inline itemEditor – from simply naming a class to creating a complex class right within the MXML tags. By naming the property of the editor class which contains the final editor value, the DataGrid can retreive the value from the editor instance and replace the current value in the data.

The next article covers more complex itemEditors and editing events.