Item editors let you modify the value of a cell of a list-based control. The DataGrid, List, and Tree controls support item editors.
For an introduction to item renderers and item editors, see MX item renderers and item editors.
The following sequence of steps occurs when a cell in a list-based control is edited:
User releases the mouse button while over a cell, tabs to a cell, or in another way attempts to edit a cell.
Flex dispatches the itemEditBeginning event. You can use this event to disable editing of a specific cell or cells. For more information, see Example: Preventing a cell from being edited.
Flex dispatches the itemEditBegin event to open the item editor. You can use this event to modify the data passed to the item editor. For more information, see Example: Modifying data passed to or received from an item editor.
The user edits the cell.
The user ends the editing session. Typically the cell editing session ends when the user removes focus from the cell.
Flex dispatches the itemEditEnd event to close the item editor and update the list-based control with the new cell data. You can use this event to modify the data returned to the cell, validate the new data, or return data in a format other than the format returned by the item editor. For more information, see Example: Modifying data passed to or received from an item editor.
The new data value appears in the cell.
The DataGrid, List, and Tree controls include an editable property that you set to true to let users edit the contents of the control. By default, the value of the editable property is false, which means that you cannot edit the cells. For a DataGrid control, setting the editable property to true enables editing for all columns of the grid. You can disable editing for any column by setting the DatagridColumn.editable property to false.
Your list-based controls can use the default item editor (TextInput control), a custom item editor, or a custom item renderer as an editor. The rendererIsEditor property of the list-based controls determines whether you can use an item renderer as an item editor, as the following table shows:
|
rendererIsEditor property |
itemRenderer property |
itemEditor property |
|---|---|---|
|
false (default) |
Specifies the item renderer. |
Specifies the item editor. Selecting the cell opens the item editor as defined by the itemEditor property. If the itemEditor property is undefined, use the default item editor (TextInput control). |
|
true |
Specifies the item renderer to display the cell contents. You can use the item renderer as an item editor. |
Ignored. |
As this table shows, the state of the rendererIsEditor property defines whether to use a custom item renderer as the item editor, or a custom item editor. If you set the rendererIsEditor property to true, Flex uses the item renderer as an item editor, and ignores the itemEditor property.
For an example, see Example: Using an item renderer as an item editor.
By default, Flex expects an item editor to return a single value to the list-based control. You use the editorDataField property of the list-based control to specify the property of the item editor that contains the new data. Flex converts the value to the appropriate data type for the cell.
The default item editor is a TextInput control. Therefore, the default value of the editorDataField property is "text", which corresponds to the text property of the TextInput control. If you specify a custom item editor, you also set the editorDataField property to the appropriate property of the item editor, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\dropin\DropInNumStepper.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
]);
]]>
</fx:Script>
<mx:DataGrid id="myDG" dataProvider="{myDP}"
variableRowHeight="true"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="label1" headerText="Order #"/>
<mx:DataGridColumn dataField="quant"
headerText="Qty"
itemEditor="mx.controls.NumericStepper"
editorDataField="value"
/>
</mx:columns >
</mx:DataGrid>
</s:Application>
In the preceding example, you use a NumericStepper control as the item editor, and therefore set the editorDataField property to "value", the property of the NumericStepper control that contains the new cell data.
An item editor can contain more than a single component. For example, the following item editor contains a parent VBox container with a child CheckBox control used to edit the cell:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\EditorDGCheckBox.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
backgroundColor="yellow">
<fx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
]]>
</fx:Script>
<mx:CheckBox id="followUpCB" label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"
updateComplete="cbSelected=followUpCB.selected;"/>
</mx:VBox>
In the preceding example, when the user selects the cell, Flex displays the CheckBox control in a yellow background, as defined by the parent VBox container. The user then selects or deselects the CheckBox control to set the new value for the cell.
To return a value to the list-based control, the VBox container defines a new property named cbSelected. This is necessary because you can only set the editorDataField property to a property of the top-level component of the item editor. That means you cannot set editorDataField to the selected property of the CheckBox control when it is a child of the VBox container.
You use the updateComplete event to set the value of the cbSelected property in case the user selects the cell to open the CheckBox control, but does not change the state of the CheckBox control.
In the following example, you use this item editor in a DataGrid control that displays a list of customer contacts. The list includes the company name, contact name, and phone number, and a column that indicates whether you must follow up with that contact.
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\MainDGCheckBoxEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="650">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05' , FollowUp: false}
]);
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
itemEditor="myComponents.EditorDGCheckBox"
editorDataField="cbSelected"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
Notice that the editorDataField property is set to cbSelected, the new property of the VBox container.
You also use this same mechanism with an inline item renderer that contains multiple controls. For example, you can modify the previous DataGrid example to use an inline item editor, rather than an item editor component, as the following code shows:
<?xml version="1.0"?>
<!-- itemRenderers\inline\InlineDGCheckBoxEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="650">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05' , FollowUp: false}
]);
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
editorDataField="cbSelected">
<mx:itemEditor>
<fx:Component>
<mx:VBox backgroundColor="yellow">
<fx:Script>
<![CDATA[
// Define a property for returning
// the new value to the cell.
[Bindable]
public var cbSelected:Boolean;
]]>
</fx:Script>
<mx:CheckBox id="followUpCB"
label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"/>
</mx:VBox>
</fx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</s:Application>
When an item editor appears, it appears as a pop-up control above the selected cell of the list-based control. The list-based control also hides the current value of the cell.
The CheckBox control in the previous example, Defining a property to return data, sizes itself to 100% for both width and height, and the VBox container sets its backgroundColor style property to yellow. By sizing the item editor to the size of the cell, and by setting the background color of the container, you completely cover the underlying cell.
The following table describes the properties of the list-based controls that you can use to size the item editor:
|
Property |
Description |
|---|---|
|
editorHeightOffset |
Specifies the height of the item editor, in pixels, relative to the size of the cell for a DataGridColumn control, or the text field of a Tree control. |
|
editorWidthOffset |
Specifies the width of the item editor, in pixels, relative to the size of the cell for a DataGridColum control, or the text field of a Tree control. |
|
editorXOffset |
Specifies the x location of the upper-left corner of the item editor, in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or from the upper-left corner of the text field of a Tree control. |
|
editorYOffset |
Specifies the y location of the upper-left corner of the item editor, in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or from the upper-left corner of the text field of a Tree control. |
The following code modifies the definition of the DataGridColumn control from the previous section to use the editorXOffset and editorYOffset properties to move the item editor down and to the right by 15 pixels so that it has a more prominent appearance in the DataGrid control:
<?xml version="1.0"?>
<!-- itemRenderers\inline\InlineDGCheckBoxEditorWithOffsets.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="650">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05' , FollowUp: false}
]);
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
editorDataField="cbSelected"
editorXOffset="15"
editorYOffset="15">
<mx:itemEditor>
<fx:Component>
<mx:VBox backgroundColor="yellow">
<fx:Script>
<![CDATA[
// Define a property for returning
// the new value to the cell.
[Bindable]
public var cbSelected:Boolean;
]]>
</fx:Script>
<mx:CheckBox id="followUpCB"
label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"/>
</mx:VBox>
</fx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</s:Application>
When you use the default item editor in a list-based control, you can edit the cell value, and then press the Enter key to move focus to the next cell in the control. When you create a simple item editor that contains only a single component, and that component implements the IFocusable interface, the item editor also responds to the Enter key. The following components implement the IFocusable interface: Accordion, Button, ButtonBar, ComboBase, DateChooser, DateField, ListBase, MenuBar, NumericStepper, TabNavigator, TextArea, and TextInput.
In the following example, you define a complex item renderer with a VBox container as the top-level component and a CheckBox control as its child component:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\EditorDGCheckBox.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
backgroundColor="yellow">
<fx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
]]>
</fx:Script>
<mx:CheckBox id="followUpCB" label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"
updateComplete="cbSelected=followUpCB.selected;"/>
</mx:VBox>
When this item editor opens, the CheckBox control can obtain focus for editing, but pressing the Enter key does not move focus to the next cell because the parent VBox container does not implement the IFocusManagerComponent interface. You can modify this example to implement the IFocusManagerComponent interface, as the following code shows:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\EditorDGCheckBoxFocusable.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
backgroundColor="yellow"
implements="mx.managers.IFocusManagerComponent" >
<fx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
// Implement the drawFocus() method for the VBox.
override public function drawFocus(isFocused:Boolean):void {
// This method can be empty, or you can use it
// to make a visual change to the component.
}
]]>
</fx:Script>
<mx:CheckBox id="followUpCB"
label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"
updateComplete="cbSelected=followUpCB.selected;"/>
</mx:VBox>
While the IFocusManagerComponent interface defines several properties and methods, the UIComponent class defines or inherits implementations for all of them except for the drawFocus() method. Therefore, you only have to implement that one method so that your item editor responds to the Enter key.
A list component dispatches the following events as part of the cell editing process: the itemEditBeginning, itemEditBegin, and the itemEditEnd events. The list-based controls define default event listeners for all three of these events.
You can write your own event listeners for one or more of these events to customize the editing process. When you write your own event listener, it executes before the default event listener, which is defined by the component, and then the default listener executes. For example, you can modify the data passed to or returned from an item editor. You can modify the data in the event listener for the itemEditBegin event. When it completes, the default event listener runs to continue the editing process.
However, you can replace the default event listener for the component with your own event listener. To prevent the default event listener from executing, you call the preventDefault() method from anywhere in your event listener.
Use the following events when you create an item editor:
itemEditBeginning
Dispatched when the user releases the mouse button while over a cell, tabs to a cell, or in any way attempts to edit a cell.
The list-based controls have a default listener for the itemEditBeginning event that sets the editedItemPosition property of the list-based control to the cell that has focus.
You typically write your own event listener for this event to prevent editing of a specific cell or cells. To prevent editing, call the preventDefault() method from within your event listener, which stops the default event listener from executing, and prevents any editing from occurring on the cell. For more information, see Example: Preventing a cell from being edited.
itemEditBegin
Dispatched before an item editor opens.
The list components have a default listener for the itemEditBegin event that calls the createItemEditor() method to perform the following actions:
Creates an item editor object, and copies the data property from the cell to the editor. By default, the item editor object is an instance of the TextInput control. You use the itemEditor property of the list-based control to specify a custom item editor class.
Sets the itemEditorInstance property of the list-based control to reference the item editor object.
You can write an event listener for this event to modify the data passed to the item editor. For example, you might modify the data, its format, or other information used by the item editor. For more information, see Example: Modifying data passed to or received from an item editor.
You can also create an event listener to determine which item editor you use to edit the cell. For example, you might have two different item editors. Within the event listener, you can examine the data to be edited, open the appropriate item editor by setting the itemEditor property to the appropriate editor, and then call the createItemEditor() method. In this case, first you call preventDefault() to stop Flex from calling the createItemEditor() method as part of the default event listener.
You can call the createItemEditor() method only from within the event listener for the itemEditBegin event. To create an editor at other times, set the editedItemPosition property to generate the itemEditBegin event.
itemEditEnd
Dispatched when the cell editing session ends, typically when focus is removed from the cell.
The list components have a default listener for this event that copies the data from the item editor to the data provider of the list-based control. The default event listener performs the following actions:
Uses the editorDataField property of the list-based control to determine the property of the item editor that contains the new data. The default item editor is the TextInput control, so the default value of the editorDataField property is "text" to specify that the text property of the TextInput control contains the new cell data.
Depending on the reason for ending the editing session, the default event listener calls the destroyItemEditor() method to close the item editor. For more information, see Determining the reason for an itemEditEnd event.
You typically write an event listener for this event to perform the following actions:
Modify the data returned from the item editor.
In your event listener, you can modify the data returned by the editor to the list-based control. For example, you can reformat the data before returning it to the list-based control.
Examine the data entered into the item editor:
In your event listener, you can examine the data entered into the item editor. If the data is incorrect, you can call the preventDefault() method to stop Flex from passing the new data back to the list-based control and from closing the editor.
Each editable list-based control has a corresponding class that defines the event object for the cell editing events, as the following table shows:
Notice that the event class for the List and Tree controls is ListEvent.
When defining the event listener for a list-based control, ensure that you specify the correct type for the event object passed to the event listener, as the following example shows for a DataGrid control:
public function myCellEndEvent(event:DataGridEvent):void {
// Define event listener.
}
From within an event listener, you can access the current value of the cell being edited, the new value entered by the user, or the item editor used to edit the cell.
To access the current value of a cell, you use the editedItemRenderer property of the list-based control. The editedItemRenderer property contains the data that corresponds to the cell being edited. For List and Tree controls, this property contains the data provider element for the cell. For a DataGrid control, it contains the data provider element for the entire row of the DataGrid.
To access the new cell value and the item editor, you use the itemEditorInstance property of the list-based control. The itemEditorInstance property is not initialized until after the event listener for the cellBeginEvent listener executes. Therefore, you typically access the itemEditorInstance property only from within the event listener for the itemEditEnd event.
The following example shows an event listener for the itemEditEnd event that uses these properties:
<?xml version="1.0"?>
<!-- itemRenderers\events\EndEditEventAccessEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
]);
// Define event listener for the itemEditEnd event.
private function getCellInfo(event:DataGridEvent):void {
// Get the cell editor and cast it to TextInput.
var myEditor:TextInput =
TextInput(event.currentTarget.itemEditorInstance);
// Get the new value from the editor.
var newVal:String = myEditor.text;
// Get the old value.
var oldVal:String =
event.currentTarget.editedItemRenderer.data[event.dataField];
// Write out the cell coordinates, new value,
// and old value to the TextArea control.
cellInfo.text = "cell edited.\n";
cellInfo.text += "Row, column: " + event.rowIndex + ", " +
event.columnIndex + "\n";
cellInfo.text += "New value: " + newVal + "\n";
cellInfo.text += "Old value: " + oldVal;
}
]]>
</fx:Script>
<mx:TextArea id="cellInfo" width="300" height="150" />
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="getCellInfo(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
In this example, you access the item editor, and cast it to the correct editor class. The default item editor is a TextInput control, so you cast it to TextInput. If you had defined a custom item editor, you would cast it to that class. After you have a reference to the item editor, you can access its properties to obtain the new cell value.
To access the old value of the cell, you use the editedItemRenderer property of the DataGrid control. You then use the dataField property of the event object to access the data property for the edited column.
A user can end a cell editing session in several ways. In the body of the event listener for the itemEditEnd event, you can determine the reason for the event, and then handle it accordingly.
Each event class for a list-based control defines the reason property, which contains a value that indicates the reason for the event. The reason property has the following values:
|
Value |
Description |
|---|---|
CANCELLED |
Specifies that the user canceled editing and that they do not want to save the edited data. Even if you call the preventDefault() method from within your event listener for the itemEditEnd event, Flex still calls the destroyItemEditor() method to close the editor. |
NEW_COLUMN |
(DataGrid only) Specifies that the user moved focus to a new column in the same row. In an event listener, you can let the focus change occur, or prevent it. For example, your event listener might check that the user entered a valid value for the cell currently being edited. If not, you can prevent the user from moving to a new cell by calling the preventDefault() method. In this case, the item editor remains open, and the user continues to edit the current cell. If you call the preventDefault() method and also call the destroyItemEditor() method, you block the move to the new cell, but the item editor closes. |
NEW_ROW |
Specifies that the user moved focus to a new row. You handle this value for the reason property similar to the way you handle the NEW_COLUMN value. |
OTHER |
Specifies that the list-based control lost focus, was scrolled, or is somehow in a state where editing is not allowed. Even if you call the preventDefault() method from within your event listener for the itemEditEnd event, Flex still calls the destroyItemEditor() method to close the editor. |
The following example uses the itemEditEnd event to ensure that the user did not enter an empty String in a cell. If there is an empty String, the itemEditEnd event calls preventDefault() method to prohibit the user from removing focus from the cell until the user enters a valid value. However, if the reason property for the itemEditEnd event has the value CANCELLED, the event listener does nothing:
<?xml version="1.0"?>
<!-- itemRenderers\events\EndEditEventFormatter.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.formatters.NumberFormatter;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
]);
private var myFormatter:NumberFormatter=new NumberFormatter();
public function formatData(event:DataGridEvent):void {
// Check the reason for the event.
if (event.reason == DataGridEventReason.CANCELLED)
{
// Do not update cell.
return;
}
// Get the new data value from the editor.
var newData:String=
TextInput(event.currentTarget.itemEditorInstance).text;
if(newData == "")
{
// Prevent the user from removing focus,
// and leave the cell editor open.
event.preventDefault();
// Write a message to the errorString property.
// This message appears when the user
// mouses over the editor.
TextInput(myGrid.itemEditorInstance).errorString=
"Enter a valid string.";
}
}
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="formatData(event);">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
In this example, if the user's reason for the event is CANCELLED, the event listener does nothing.
If the reason is NEW_COLUMN, NEW_ROW, or OTHER, the event listener performs the following actions:
Checks if the new cell value is an empty String.
If it is an empty String, the event listener calls the preventDefault() method to prevent Flex from closing the editor and from updating the cell with the empty String.
Writes a message to the errorString property of the TextInput control. This message causes a red box to appear around the TextInput control, and the message appears as a tooltip when the user moves the mouse over the cell.
From within an event listener for the itemEditBeginning event, you can inspect the cell being edited, and prevent the edit from occurring. This technique is useful when you want to prevent editing of a specific cell or cells, but allow editing of other cells.
For example, the DataGrid control uses the editable property to make all cells in the DataGrid control editable. You can override that for a specific column, using the editable property of a DataGridColumn, but you cannot enable or disable editing for specific cells.
To prevent cell editing, call the preventDefault() method from within your event listener for the itemEditBeginning event, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\events\EndEditEventPreventEdit.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99}
]);
// Define event listener for the cellEdit event
// to prohibit editing of the Album column.
private function disableEditing(event:DataGridEvent):void {
if(event.columnIndex==1)
{
event.preventDefault();
}
}
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditBeginning="disableEditing(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
Although the preceding example uses the column index, you could inspect any property of the DataGrid, or of the cell being edited, to make your decision about allowing the user to edit the cell.
You can use the itemEditBegin and itemEditEnd events to examine the data passed to and from the item editor, and modify it if necessary. For example, you could reformat the data, extract a part of the data for editing, or examine the data to validate it.
In the next example, you use a NumericStepper control to edit the Price column of a DataGrid control. The itemEditBegin event modifies the data passed to the NumericStepper to automatically add 20% to the price when you edit it. Use the NumericStepper control to modify the updated price as necessary.
<?xml version="1.0"?>
<!-- itemRenderers\events\BeginEditEventAccessEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.controls.NumericStepper;
import mx.collections.ArrayCollection;
import mx.controls.listClasses.IDropInListItemRenderer;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
{Artist:'Pavement', Album:'Crooked Rain, Crooked Rain', Price:10.99},
{Artist:'Pavement', Album:'Wowee Zowee', Price:12.99},
{Artist:'Pavement', Album:'Brighten the Corners', Price:11.99},
{Artist:'Pavement', Album:'Terror Twilight', Price:11.99}
]);
// Handle the itemEditBegin event.
private function modifyEditedData(event:DataGridEvent):void
{
// Get the name of the column being editted.
var colName:String = myDataGrid.columns[event.columnIndex].dataField;
if(colName=="Price")
{
// Handle the event here.
event.preventDefault();
// Creates an item editor.
myDataGrid.createItemEditor(event.columnIndex,event.rowIndex);
// All item editors must implement the IDropInListItemRenderer interface
// and the listData property.
// Initialize the listData property of the editor.
IDropInListItemRenderer(myDataGrid.itemEditorInstance).listData =
IDropInListItemRenderer(myDataGrid.editedItemRenderer).listData;
// Copy the cell value to the NumericStepper control.
myDataGrid.itemEditorInstance.data = myDataGrid.editedItemRenderer.data;
// Add 20 percent to the current price.
NumericStepper(myDataGrid.itemEditorInstance).value +=
0.2 * NumericStepper(myDataGrid.itemEditorInstance).value;
}
}
]]>
</fx:Script>
<mx:DataGrid id="myDataGrid" dataProvider="{myDP}"
editable="true"
itemEditBegin="modifyEditedData(event);"
rowHeight="60">
<mx:columns>
<mx:DataGridColumn dataField="Artist" />
<mx:DataGridColumn dataField="Album" width="130" />
<mx:DataGridColumn dataField="Price" editorDataField="value">
<mx:itemEditor>
<fx:Component>
<mx:NumericStepper stepSize="0.01" maximum="500"/>
</fx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</s:Application>
You could use one of the Flex formatter classes to format data returned from an item editor. In the following example, you let the user edit the Price column of a DataGrid control. You then define an event listener for the itemEditEnd event that uses the NumberFormatter class to format the new cell value so that it contains only two digits after the decimal point, as the following code shows:
<?xml version="1.0"?>
<!-- itemRenderers\events\EndEditEventFormatter.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" >
<fx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.formatters.NumberFormatter;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
]);
// Define the number formatter.
private var myFormatter:NumberFormatter=new NumberFormatter();
// Define the eventlistner for the itemEditEnd event.
public function formatData(event:DataGridEvent):void {
// Check the reason for the event.
if (event.reason == DataGridEventReason.CANCELLED)
{
// Do not update cell.
return;
}
// Get the new data value from the editor.
var newData:String=
TextInput(event.currentTarget.itemEditorInstance).text;
// Determine if the new value is an empty String.
if(newData == "") {
// Prevent the user from removing focus,
// and leave the cell editor open.
event.preventDefault();
// Write a message to the errorString property.
// This message appears when the user
// mouses over the editor.
TextInput(myGrid.itemEditorInstance).errorString=
"Enter a valid string.";
return;
}
// For the Price column, return a value
// with a precision of 2.
if(event.dataField == "Price") {
myFormatter.precision=2;
TextInput(myGrid.itemEditorInstance).text=
myFormatter.format(newData);
}
}
]]>
</fx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="formatData(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
If you set the rendererIsEditor property of the DataGrid, List, or Tree control to true, the control uses the default TextInput control as the item editor, or the item renderer that specifies the itemRenderer property. If you specify an item renderer, you must ensure that you include editable controls in it so that the user can edit values.
For example, the following item renderer displays information in the cell by using the TextInput control, and lets the user edit the cell's contents:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\MyContactEditable.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
[Bindable]
public var newContact:String;
]]>
</fx:Script>
<mx:Label id="title" text="{data.label1}"/>
<mx:Label id="contactLabel" text="Last Contacted By:"/>
<mx:TextInput id="contactTI"
editable="true"
text="{data.Contact}"
change="newContact=contactTI.text;"/>
</mx:VBox>
You can use this item renderer with a DataGrid control, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\MainAppEditable.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
height="700" width="700">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{label1: "Order #2314", Contact: "John Doe",
Confirmed: false, Photo: "john_doe.jpg", Sent: false},
{label1: "Order #2315", Contact: "Jane Doe",
Confirmed: true, Photo: "jane_doe.jpg", Sent: false}
]);
]]>
</fx:Script>
<mx:DataGrid id="myDG"
width="500" height="250"
dataProvider="{initDG}"
variableRowHeight="true"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Photo"
editable="false"/>
<mx:DataGridColumn dataField="Contact"
width="200"
editable="true"
rendererIsEditor="true"
itemRenderer="myComponents.MyContactEditable"
editorDataField="newContact"/>
<mx:DataGridColumn dataField="Confirmed"
editable="true"
rendererIsEditor="true"
itemRenderer="mx.controls.CheckBox"
editorDataField="selected"/>
<mx:DataGridColumn dataField="Sent"
editable="true"
rendererIsEditor="false"
itemEditor="mx.controls.CheckBox"
editorDataField="selected"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
In the previous example, you use the item renderer as the item editor by setting the rendererIsEditor property to true in the second and third columns of the DataGrid control.
Just as you can validate data in other types of controls, you can validate data in the cells of list-based controls. To do so, you can create an item renderer or item editor that incorporates a data validator. For more information about data validators, see Validating Data.
The following example shows the code for the validating item editor component. It uses a TextInput control to edit the field. In this example, you assign a PhoneNumberValidator validator to the text property of the TextInput control to validate the user input:
<?xml version="1.0"?>
<!-- itemRenderers\validator\myComponents\EditorPhoneValidator.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
[Bindable]
public var returnPN:String;
]]>
</fx:Script>
<fx:Declarations>
<mx:PhoneNumberValidator id="pnV"
source="{newPN}"
property="text"
trigger="{newPN}"
triggerEvent="change"
required="true"/>
</fx:Declarations>
<mx:TextInput id="newPN"
text="{data.phone}"
updateComplete="returnPN=newPN.text;"
change="returnPN=newPN.text;"/>
</mx:VBox>
If the user enters an incorrect phone number, the PhoneNumberValidator draws a red box around the editor and shows a validation error message when the user moves the mouse over it.
The following example shows the code for the application that uses this item editor:
<?xml version="1.0" ?>
<!-- itemRenderers\validator\MainDGValidatorEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{name: 'Bob Jones', phone: '413-555-1212',
email: 'bjones@acme.com'},
{name: 'Sally Smith', phone: '617-555-5833',
email: 'ssmith@acme.com'},
]);
]]>
</fx:Script>
<mx:DataGrid id="dg"
width="500" height="200"
editable="true"
dataProvider="{initDG}">
<mx:columns>
<mx:DataGridColumn dataField="name"
headerText="Name" />
<mx:DataGridColumn dataField="phone"
headerText="Phone"
itemEditor="myComponents.EditorPhoneValidator"
editorDataField="returnPN"/>
<mx:DataGridColumn dataField="email" headerText="Email" />
</mx:columns>
</mx:DataGrid>
</s:Application>
For examples of using item editors with the DataGrid control, see Returning data from an MX item editor.
You can add an item editor to a List control to let users edit the information for each state, as the following item editor shows:
<?xml version="1.0"?>
<!-- itemRenderers\list\myComponents\EditorStateInfo.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<mx:TextInput id="newLabel" text="{data.label}" />
<mx:TextInput id="newData" text="{data.data}" />
<mx:TextInput id="newWebPage" text="{data.webPage}" />
</mx:VBox>
You define an item editor that contains three TextInput controls that let the user edit the state name, capital, or web address. This item editor returns three values, so you write an event listener for the itemEditEnd event to write the values to the data provider of the List control, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\list\MainListStateRendererEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
height="700" width="700">
<fx:Script>
<![CDATA[
import mx.events.ListEvent;
import myComponents.EditorStateInfo;
// Define the event listener.
public function processData(event:ListEvent):void {
// Disable copying data back to the control.
event.preventDefault();
// Get new label from editor.
myList.editedItemRenderer.data.label =
EditorStateInfo(event.currentTarget.itemEditorInstance).newLabel.text;
// Get new data from editor.
myList.editedItemRenderer.data.data =
EditorStateInfo(event.currentTarget.itemEditorInstance).newData.text;
// Get new webPage from editor.
myList.editedItemRenderer.data.webPage =
EditorStateInfo(event.currentTarget.itemEditorInstance).newWebPage.text;
// Close the cell editor.
myList.destroyItemEditor();
// Notify the list control to update its display.
myList.dataProvider.itemUpdated(myList.editedItemRenderer);
}
]]>
</fx:Script>
<mx:List id="myList"
height="180" width="250"
editable="true"
itemRenderer="myComponents.RendererState"
itemEditor="myComponents.EditorStateInfo"
variableRowHeight="true"
itemEditEnd="processData(event);">
<mx:dataProvider>
<fx:Object label="Alaska"
data="Juneau"
webPage="http://www.state.ak.us/"/>
<fx:Object label="Alabama"
data="Montgomery"
webPage="http://www.alabama.gov/" />
<fx:Object label="Arkansas"
data="Little Rock"
webPage="http://www.state.ar.us/"/>
</mx:dataProvider>
</mx:List>
</s:Application>
This example uses the RendererState.mxml renderer. You can see that renderer in the section Example: Using an item renderer with an MX List control.
You can use a DateField or ComboBox control as a drop-in item editor with the List control. However, when the data provider is a collection of Objects, you have to set the labelField property of the List control to the name of the field in the data provider modified by the DateField or ComboBox control, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\list\ListEditorDateField.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.*;
import mx.controls.DateField;
import mx.collections.ArrayCollection;
[Bindable]
private var catalog:ArrayCollection = new ArrayCollection([
{confirmed: new Date(), Location: "Spain"},
{confirmed: new Date(2006,0,15), Location: "Italy"},
{confirmed: new Date(2004,9,24), Location: "Bora Bora"},
{confirmed: new Date(), Location: "Vietnam"}
]);
]]>
</fx:Script>
<mx:List id="myList"
width="300" height="300"
rowHeight="50"
dataProvider="{catalog}"
editable="true"
labelField="confirmed"
itemEditor="mx.controls.DateField"
editorDataField="selectedDate"/>
</s:Application>
In this example, you specify "confirmed" as the value of the labelField property to specify that the DateField control modifies that field of the data provider.
In a Tree control, you often display a single label for each node in the tree. However, the data provider for each node may contain additional data that is normally hidden from view.
In this example, you use the Tree control to display contact information for different companies. The Tree control displays the company name as a branch node, and different department names within the company as leaf nodes. Selecting any node opens a custom item editor that lets you modify the phone number or contact status of the company or for any department in the company.
The top node in the Tree control is not editable. Therefore, this example uses the itemEditBeginning event to determine if the user selects the top node. If selected, the event listener for the itemEditBeginning event prevents editing from occurring, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\tree\MainTreeEditor.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="600" height="600">
<fx:Script>
<![CDATA[
import mx.events.ListEvent;
import myComponents.TreeEditor;
private var contacts1:Object =
{label: "top", children: [
{label: "Acme", status: true, phone: "243-333-5555", children: [
{label: "Sales", status: true, phone: "561-256-5555"},
{label: "Support", status: false, phone: "871-256-5555"}
]},
{label: "Ace", status: true, phone: "444-333-5555", children: [
{label: "Sales", status: true, phone: "232-898-5555"},
{label: "Support", status: false, phone: "977-296-5555"},
]},
{label: "Platinum", status: false, phone: "521-256-5555"}
]};
private function initCatalog(cat:Object):void {
myTree.dataProvider = cat;
}
// Define the event listener for the itemEditBeginning event
// to disable editing when the user selects
// the top node in the tree.
private function disableEditing(event:ListEvent):void {
if(event.rowIndex==0) {
event.preventDefault();
}
}
// Define the event listener for the itemEditEnd event
// to copy the updated data back to the data provider
// of the Tree control.
public function processData(event:ListEvent):void {
// Disable copying data back to the control.
event.preventDefault();
// Get new phone number from editor.
myTree.editedItemRenderer.data.phone =
TreeEditor(event.currentTarget.itemEditorInstance).contactPhone.text;
// Get new status from editor.
myTree.editedItemRenderer.data.status =
TreeEditor(event.currentTarget.itemEditorInstance).confirmed.selected;
// Close the cell editor.
myTree.destroyItemEditor();
// Notify the list control to update its display.
myTree.dataProvider.itemUpdated(myTree.editedItemRenderer);
}
]]>
</fx:Script>
<mx:Tree id="myTree"
width="400" height="400"
editable="true"
itemEditor="myComponents.TreeEditor"
editorHeightOffset="75" editorWidthOffset="-100"
editorXOffset="40" editorYOffset="30"
creationComplete="initCatalog(contacts1);"
itemEditBeginning="disableEditing(event);"
itemEditEnd="processData(event);"/>
</s:Application>
You specify the custom item editor using the itemEditor property of a Tree control. You also use the editorHeightOffset, editorWidthOffset, editorXOffset, and editorYOffset properties to position the item editor.
The following item editor, defined in the file TreeEditor.mxml, lets you edit the data associated with each item in a Tree control:
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- itemRenderers/tree/myComponents/TreeEditor.mxml -->
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
// Define variables for the new data.
public var newPhone:String;
public var newConfirmed:Boolean;
]]>
</fx:Script>
<!-- Display item label.-->
<mx:Label text="{data.label}"/>
<!-- Display the text 'Phone:' and let the user edit it.-->
<mx:HBox>
<mx:Text text="Phone:"/>
<mx:TextInput id="contactPhone"
width="150"
text="{data.phone}"
change="newPhone=contactPhone.text;"/>
</mx:HBox>
<!-- Display the status using a CheckBox control
and let the user edit it.-->
<mx:CheckBox id="confirmed"
label="Confirmed"
selected="{data.status}"
click="newConfirmed=confirmed.selected;"/>
</mx:VBox>
Navigation
Adobe and Adobe Flash are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.