Flex DataGrid Editing Cells

Flex datagrids provide an easy way to edit data. However one minor issue is that by default editable cells have no visual indication that they are actually editable.

You can add a graphical or textual indication that is a cell is editable with an item renderer.

Here's the code to do this:

view plain print about
1<?xml version="1.0" encoding="utf-8"?>
2<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()" viewSourceURL="srcview/index.html">
3
    
4    <mx:DataGrid id="myDG" dataProvider="{customers}" rowCount="5" width="300" height="200" editable="true">
5        <mx:columns>

6            <mx:DataGridColumn headerText="Name" width="100" dataField="name" editable="false" editorDataField="text">
7                <mx:itemRenderer>

8                    <mx:Component>

9                        <mx:HBox horizontalScrollPolicy="off">
10                            <mx:Label text="{data.name}" />
11                            <mx:Spacer width="100%" />
12                            <mx:Label text="+" click="outerDocument.editCell(0)" toolTip="Edit" />
13                        </mx:HBox>

14                    </mx:Component>

15                </mx:itemRenderer>

16                <mx:itemEditor>

17                    <mx:Component>

18                        <mx:TextInput text="{data.name}" />
19                    </mx:Component>

20                </mx:itemEditor>

21            </mx:DataGridColumn>

22            
23            <mx:DataGridColumn headerText="Addresss" dataField="address" width="200" editable="false" editorDataField="text">
24                <mx:itemRenderer>

25                    <mx:Component>
26                        <mx:HBox horizontalScrollPolicy="off">
27                            <mx:Label text="{data.address}" />
28                            <mx:Spacer width="100%" />
29                            <mx:Label text="+" click="outerDocument.editCell(1)" toolTip="Edit" />
30                        </mx:HBox>

31                    </mx:Component>

32                </mx:itemRenderer>

33                <mx:itemEditor>

34                    <mx:Component>
35                        <mx:TextInput text="{data.address}" />
36                    </mx:Component>

37                </mx:itemEditor>
38            </mx:DataGridColumn>
39        </mx:columns>
40    </mx:DataGrid>
41    
42    <mx:Model id="custdata">
43        <customers>
44            <customer>
45                <name>Cust1</name>
46                <address>Address1</address>
47            </customer>
48            <customer>
49                <name>Cust2</name>
50                <address>Address2</address>
51            </customer>
52            <customer>
53                <name>Cust3</name>
54                <address>Address3</address>
55            </customer>        
56        </customers>
57    </mx:Model>

58
59    <mx:Script>
60        <![CDATA[
61            import mx.collections.ArrayCollection;
62            
63            [Bindable] private var customers:ArrayCollection = new ArrayCollection();
64
65            private function init():void {
66                customers = new ArrayCollection(custdata.customer);
67            }
68            
69            public function editCell(column:Number):void {
70                myDG.editedItemPosition = {columnIndex:column, rowIndex:myDG.selectedIndex}
71            }
72        ]]>
73    </mx:Script>
74
75</mx:Application>

Code works in Flex 2 and Flex 3.

There's just a few thing to note:

  • The datagrid needs to be marked as editable but you don't need to make the columns editable. The editable cell can set by setting the editedItemPosition property of the datagrid.
  • The current row can be obtained by looking at the value of the selectedIndex property.
  • You need to create an item editor as well as an item renderer and set the editorDataField for editing cells. This sets the value of the field after it has been edited.
  • This example uses a "+" to indicate that a cell is editable but you could use an image instead.

Here what the code looks look when run (right click to view source and/or download):

Related Blog Entries

TweetBacks
Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
I'm trying this in Flex Builder 3 and I get the error:

Could not resolve <mx:itemRenderer> to a component implementation.
# Posted By Nuno Morgadinho | 9/18/07 12:35 AM
Tried it out on Flex 3 (M2 beta 1 release) and it works fine here. Have you made any changes to the code?
# Posted By Justin Mclean | 9/19/07 9:33 AM
This is cool - but how do I add listeners to it so I know when the user has finished editing the data in a cell?
# Posted By Alex | 12/13/07 11:26 PM
Very cool. Thank you. It helps me solve two problems:

1. adding the restrict tag to the input field.
2. giving the user info on which one is editable.

I made some changes in order to center the field values and took out the spacer.

<mx:Component>
<mx:HBox click="outerDocument.editCell(0)" horizontalAlign="center">
<mx:Label text="{data.MaxCapacity}" width="93%" paddingLeft="18" />
<mx:Label textAlign="right" text="+" toolTip="Edit" width="13" />
</mx:HBox>
</mx:Component>
# Posted By brent | 5/22/08 6:55 AM
Yeah yeah check this out. Dig this, Johnson !! I made it better and really ObjOriented.

Here's your dataGrid code:

&lt;mx:DataGridColumn headerText=&quot;Quantity&quot; dataField=&quot;Quantity&quot; textAlign=&quot;center&quot; itemRenderer=&quot;path.to.your.view.EditableCellRenderer&quot;
itemEditor=&quot;path.to.your.view.EditableCellEditor&quot; /&gt;   

And here's your editable cell editor:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:TextInput xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot;
   width=&quot;100%&quot; height=&quot;100%&quot;
   restrict=&quot;0-9&quot;&gt;
   
   &lt;mx:Script&gt;
      &lt;![CDATA[
         import mx.controls.DataGrid;
         
         /**
          * Override data setter to set cell text according to the dataField
          */
         public override function set data(value:Object):void
         {
            var dg:DataGrid = owner as DataGrid;
            text = value[dg.columns[dg.editedItemPosition.columnIndex].dataField];
         }
      ]]&gt;
   &lt;/mx:Script&gt;
&lt;/mx:TextInput&gt;

This is even better since you don't need to know which order your dataGrid column is and cuts your code by like 90%.
# Posted By Brent | 5/29/08 6:44 AM
If you're using Flex 3 you want to add horizontalScrollPolicy="off" on the HBox renderers.
# Posted By Justin Mclean | 5/18/09 6:04 PM
There is a typo in the line below..

<mx:HBoxhorizontalScrollPolicy="off">

It should be <mx:HBox horizontalScrollPolicy="off"> else you will get a compiler error.
# Posted By tarun | 7/7/09 4:42 AM
Thanks for picking that up Tarun its now fixed.
# Posted By Justin Mclean | 7/7/09 9:16 AM
Here is a better EditableCellRenderer.

public class EditableCellRenderer extends Label {
      
      [Embed(source=&quot;../../common/assets/images/icon_edit_16.gif&quot;)]
      private var icon_edit_16:Class;
         
      private var img:Image;            

/**
       * @private
       */
      private function onClickHandler(event:MouseEvent):void{         
         event.stopImmediatePropagation();            
         if(listData &amp;&amp; listData.owner is DataGrid){               
            DataGrid(listData.owner).editedItemPosition =
                {columnIndex:listData.columnIndex, rowIndex:DataGrid(listData.owner).selectedIndex}
         }
      }
      
/**
       * @private
       */
      override protected function createChildren ():void {      
         super.createChildren();         
         //mx_internal::border.visible = false;         
         if (!img){         
            img = new Image();
            img.source = icon_edit_16;   
            img.maintainAspectRatio = true;         
            img.mouseFocusEnabled = false;
            img.useHandCursor = true;
            img.buttonMode = true;
            img.mouseChildren = false;
            img.toolTip = 'Edit';
            img.styleName = this;
            img.addEventListener(MouseEvent.CLICK,onClickHandler);
            addChild(img);
         }//if
      }
      
/**
       * @private
       */
      override protected function measure():void {      
         super.measure();   
         measuredWidth = measuredWidth + img.getExplicitOrMeasuredWidth();         
      }//measure

      /**
       * @private
       */
      override protected function updateDisplayList (unscaledWidth:Number, unscaledHeight:Number):void {   
         
         super.updateDisplayList(unscaledWidth, unscaledHeight);   
         if(true){
            //Image RHS            
            img.move((unscaledWidth - img.width), ((unscaledHeight - img.height) / 2));
         } else {
            //Image LHS
            textField.move(img.width,0);         
         }//else         
         img.setActualSize(16, 16);
         textField.setActualSize( (unscaledWidth - img.width),unscaledHeight);
      }//updateDisplayList      
   }
# Posted By Vijay Anand Mareddy | 12/8/09 2:34 AM