Adding Dynamic Rows To Flex DataGrid

Skill

Adding Dynamic Rows To Flex DataGrid

Posted in:

One of the many things people want to do when using a DataGrid is adding new rows to the data. Now this can be done a bunch of different ways. One method is using a popup to handle adding items to the collection the grid is bound to. Another method is to add another row directly into the grid. This tutorial is going to focus on the second of the above methods.

To demonstrate what we are going to build today you can check out the below example application. The demo is a basic task application which you can add to by clicking on the row entitled "Click to Add Task". Once the task has been added to the list you can modify its other attributes. That pretty much sums up the capabilities of the application. Now compared to using a popup this is slightly more complicated but I assure you that it isn't too bad. You can grab the source code for this example also.

Get Adobe Flash player

To get things rolling we are going to throw together a very quick interface that we will use for the demo application. You can see the code below, but basically we have the root application tag and then a DataGrid which fills the rest of the area. The grid has three pretty self explanatory columns. One item of note is that I have set sortableColumns equal to false. I have done this because with using a row to add more items the sorting will not work quite right unless some extra code is added. If anyone would like to see the code needed to make that work simply leave comment letting me know and I will cover it in a later tutorial.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="absolute" width="400" height="200">
  <mx:DataGrid id="grid" width="100%" height="100%"
     sortableColumns="false" editable="true">
    <mx:columns>
      <mx:DataGridColumn headerText="Title" dataField="title" width="250" />
      <mx:DataGridColumn headerText="Priority" dataField="priority" width="60" />
      <mx:DataGridColumn headerText="Due Date" dataField="due"/>
    </mx:columns>
  </mx:DataGrid>
</mx:Application>

The next thing we will do is actually create a new class for holding the task information. This is done to make life easier for creating tasks and referencing the information inside them.

package
{
  [Bindable]
  public class Task
  {
    public function Task(title:String, priority:int, due:String)
    {
      this.title = title;
      this.priority = priority;
      this.due = due;
    }
   
    public var title:String;
    public var priority:int;
    public var due:String;
  }
}

Now we can start building the rest of the code beginning with code to initialize the task list. To do this I add an event handler to the main application for the creationComplete event. The handler function for this, init, is put inside a Script tag. Along with the function we also need an ArrayCollection to hold our tasks. Inside the init function I create a new ArrayCollection and add a few tasks to it.

<mx:Script>
<![CDATA[
 import mx.collections.ArrayCollection;
 
 [Bindable]
 private var tasks:ArrayCollection;
 
 private function init():void
 {
   tasks = new ArrayCollection();
   tasks.addItem(new Task("Write Tutorial", 4, "today"));
   tasks.addItem(new Task("Make Breakfast", 1, "tomorrow"));
 }
]]>
</mx:Script>

We also need to tell the DataGrid to use the ArrayCollection as the dataProvider. Here is the updated opening DataGrid tag.

<mx:DataGrid id="grid" width="100%" height="100%" editable="true"
   dataProvider="{tasks}" sortableColumns="false" >

Everything up to this point has been pretty normal when building a DataGrid but now we need to start entering pieces to handle adding new rows. A dummy row for adding new items is the first item to add. To accomplish this we modify the init function and also add a constant to hold the text we use for the dummy row. Following the code below I will explain the addItem call a little bit more.

<mx:Script>
<![CDATA[
 import mx.collections.ArrayCollection;
 
 [Bindable]
 private var tasks:ArrayCollection;
 
 private static const ADD_TASK:String = "Click to Add Task";
 
 private function init():void
 {
   tasks = new ArrayCollection();
   tasks.addItem(new Task("Write Tutorial", 4, "today"));
   tasks.addItem(new Task("Make Breakfast", 1, "tomorrow"));
   tasks.addItem({title: ADD_TASK});
 }
]]>
</mx:Script>

You can see the object that is added to the collection is a simple object with the title set to our constant. We set the title because it is the dataField property that the first column in our grid is using.
Next up is handling two events on the DataGrid itself, these are itemEditBeginning and itemEditEnd which are handled by the functions checkEdit and editEnd respectively. We will go over checkEdit first.

private function checkEdit(e:DataGridEvent):void
{
  // Do not allow editing of Add Task row except for
  // "Click to Add" column
  if(e.rowIndex == tasks.length - 1 && e.columnIndex != 0)
    e.preventDefault();
}

This function above does one thing. It checks to make sure if you are adding a task by clicking the last row you are not trying to change anything except the first column. The second function is a little more complicated. Let's take a look at editEnd.

private function editEnd(e:DataGridEvent):void
{
  // Adding a new task
  if(e.rowIndex == tasks.length - 1)
  {
    var txtIn:TextInput = TextInput(e.currentTarget.itemEditorInstance);
    var dt:Object = e.itemRenderer.data;
   
    // Add new task
    if(txtIn.text != ADD_TASK)
    {
      tasks.addItemAt(new Task(txtIn.text, 0, ""), e.rowIndex);
    }
   
    // Destroy item editor
    grid.destroyItemEditor();
   
    // Stop default behavior
    e.preventDefault();
  }
}

At the top of the function you can see that we first check to make sure the row being edited is the last one, otherwise we just let it go do its default behavior - which is to update the data provider. Once we know that the last row is being changed we need to check what the text is in the item editor. This is done by getting the itemEditorInstance and then we can cast it as a TextInput to get the text. If the text is not equal to the "Click to Add Task" text then we add a new task to the tasks ArrayCollection to the current row position - this means it will move the "Click to Add Task" item down. Then we destroy the item editor to make sure everything it kosher and cancel the default event handling.

That is pretty much it, this tutorial outlined what it takes to dynamically add row to a DataGrid or really any list based control. If anyone has any questions just leave a comment.

Tester
10/03/2008 - 02:29

Hi,
I tryed it. but, it didn't work.
First, i put as file on the lib folder(Flex Builder pro 3).
Then, i set the main.mxml file to src filder.
next, i run.
but, it didn't work.
I need your help.

and I need your dataGrid lib.
Please explain.

reply

The Fattest
10/03/2008 - 08:48

No libraries are needed for this, just the code. Just download or copy/paste the source from here.

reply

Jack
10/12/2008 - 06:29

Great example!
thanks!

reply

Bilbo
10/21/2008 - 15:14

tab key functionality is whack, i am trying to figure out how to correct that, not having much luck.

reply

The Fattest
10/21/2008 - 18:00

what are you looking to do with the tab key? I feel it works as expected.

reply

Bilbo
10/22/2008 - 08:36

well, after clicking on the "add new row" and editing the first cell I would expect the tab key to shift the focus to the next cell to the right, instead the focus is sent to the next row down.

reply

Bilbo
10/22/2008 - 09:31

i changed the editEnd function to the following to get what I expected.

private function editEnd(e:DataGridEvent):void {
  // Adding a new task
  if(e.rowIndex == dataCollection.length - 1) {
    var txtIn:Object =
      TextInput(e.currentTarget.itemEditorInstance);

    // Add new item
    if(txtIn.text != ADD_ITEM) {
      dataCollection.addItem({id: ADD_ITEM});
    }
  }
}

*edited for formatting

reply

The Fattest
10/22/2008 - 12:08

Thanks for giving us an update and sharing the your code bilbo.

reply

gopal
07/28/2009 - 05:38

hi!
The Fattest ! i am a big fan of u.
i am also stuck in a serious problem,
plz help me ,
i am trying to make a datagrid that can provide a blank cell structure in editable mode like we have in MS Excel sheet.

i want all cells to be active in the grid sothat can be edited,copy/paste and other operations like drag and drop can be enabled there

any input from ur side would be helpful

reply

gopal
07/28/2009 - 05:38

hi!
The Fattest ! i am a big fan of u.
i am also stuck in a serious problem,
plz help me ,
i am trying to make a datagrid that can provide a blank cell structure in editable mode like we have in MS Excel sheet.

i want all cells to be active in the grid sothat can be edited,copy/paste and other operations like drag and drop can be enabled there

any input from ur side would be helpful

reply

Jack
11/06/2008 - 07:36

hi. quick question....works really well...just wanted to know with a datagrid on a panel where would you place buttons...like print, save, open...ideally i thought it would be best to place them at the top of the panel but don't seem to be allowed to.
Thanks! (and if u get the chance to describe how to delete the rows that would be gr8!)

reply

Wayne
11/06/2008 - 13:44

I'm new to Flex. Will this method work for a Grid container as well? I understand that a Grid container does not have a dataProvider property instead it has a property call data. My qoal to create componments during runtime within a grid.

Thanks,
Wayne

reply

The Fattest
11/11/2008 - 20:37

wayne, you can use a component called a repeater to do what your looking for.

reply

wrightee
01/15/2009 - 05:17

One method is using a popup to handle adding items to the collection the grid is bound to.

I've been searching for days for an example of this... can anyone help? Thanks for your time, and all this code..

reply

The Fattest
04/03/2009 - 22:50

I have put up a tutorial on that exact subject.

reply

Abidd
03/24/2009 - 22:08

Hi.. Thanx for your example.. It works. btu i have a problem when i change the itemEditor to CheckBox and DateField after i change the value for CheckBox and DateField the other column cannot edit anymore and cannot add new row.. can anyone help?

Thnx.
Abid

reply

lorenaiulia
04/14/2009 - 12:21

Hi!
Thank you for the tutorial, it's been very helpful.
However, I would also like to set the 'sortableColumns' property to true even when performic this dynamic adding of rows. Could you please help me on that?
Thank you,
Lorena

reply

The Fattest
04/14/2009 - 12:33

Well, the quick answer is you have to write all your own sorting functions with specific logic to handle the add row. I can try and put something together in the next couple of days to try and demonstrate it if you think that would help.

reply

lorenaiulia
04/18/2009 - 04:05

Thank you for your suggestion. I will first try to do it myself :) I hope I can manage.
Thank you

reply

Thomas
04/21/2009 - 07:37

I'm new to Flex and I've been using your above example. It works great.

On top of this, I would like to add a remove/delete icon like this:

<mx:DataGridColumn width="9" editable="false" >
  <mx:itemRenderer>
    <mx:Component>
      <mx:Image source="@Embed(source='assets/remove.gif')" toolTip="Delete"       click="outerDocument.deleteRow(event)" verticalAlign="middle" />
    </mx:Component>
  </mx:itemRenderer>
</mx:DataGridColumn>

Based on this example:
http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=2&postId=12387

However I don't see how I can hide this icon when the row is ADD_TASK one.

Could you help?

reply

The Fattest
07/28/2009 - 08:55

You would have to have a little more complicated item renderer. Probably a custom component that overrides public override function set data and checks to see if the data is the ADD_TASK one. Then you can make the delete button invisible.

reply

Anonymous
02/12/2011 - 17:07

So I got the delete behavior working with the following code snippet -

<mx:DataGridColumn editable="false" width="20">
   <mx:itemRenderer>
      <mx:Component>
         <mx:HBox>
           <mx:Image source="remove.gif"
                   visible="{data.symbol != outerDocument.ADD_TASK}"
click="outerDocument.deleteItem(event)"/>                                                
         </mx:HBox>
      </mx:Component>
   </mx:itemRenderer>
</mx:DataGridColumn>

reply

Per Kjetil
06/15/2009 - 13:38

Hi!
I want to build an application similar to this. But i want to display the content of the datagrid as plane text as well. But i dont know how to data bind the datagrid.
Is this possible?

Thanks

reply

The Fattest
07/28/2009 - 08:58

I am not quite sure what you mean, the data is show as plain text.

reply

gopal
07/28/2009 - 05:35

hi guyz!
The Fattest ! i am a big fan of u.

plz help me ,
i am trying to make a datagrid that can provide a blank cell structure in editable mode like we have in MS Excel sheet.

any input from ur side would be helpful.

plz reply soon

reply

The Fattest
07/28/2009 - 08:59

gopal, this is going to be a big endeavor to do something like excel has, basically though I would start with filling the table with blank rows that have edit enabled. Then you might override the edit end events on the datagrid to handle edits and commits of information. That would at least get you started.

reply

gopal
07/29/2009 - 01:03

thanks for replying, Charlie!

m trying the same, filling the blank rows would also work anyways, rest of the work i am also trying @ my end

i am new to Flex and Actionscript, so plz keep updating us with your useful topics and tutorials

reply

gopal
07/31/2009 - 05:07

hi Fattest!

so have u done with some blank cells in datagrid?
actually i am working on the same but not succeeded yet

i am suggesting you the method what i am following,
in datagrid if we capture a click event or tab event for cells and wherever we click or press tab, that cell should be editable,

is it possible by adding some action script ?

reply

Shankar
08/02/2009 - 20:55

Hi,

Thanks for the code, its very helpful but I am in need to have itemEditor's for one of the columns, for ex: the "due date" could be a DateField or a dropdown to select.

Can you please show how to achieve this?

Thanks.

reply

francisco
08/08/2009 - 15:22

Besides the data provider you need to create a factory for the item editor. It should be bindable.

[Bindable]
private var automatedDP:ArrayCollection = new ArrayCollection();

[Bindable]
private var comboFactoryAutomated:ClassFactory;

You should initialize your factory as follows:

private function initializeComboFactoryAutomated():void{

automatedDP = new ArrayCollection(booleanArray);
comboFactoryAutomated = new ClassFactory(ComboBox);
comboFactoryAutomated.properties= {dataProvider:automatedDP};
}

In your datagrid definition you must the factory as itemEditor:

i hope it help you florentino ...

reply

Rukk Reddy
09/08/2009 - 08:08

hi
I got Array from DB and I populated that Array in DataGrid.My problem is how can i save total DataGrid values not single row all the rows simultanously in DB.
please can you sugggest.

Thanks In Advance,
Rukku.

reply

Samuel M.
09/29/2009 - 11:33

Rukk, I'm new to flex too.

I was thinking if you added a save function in your service layer that you called from your remote object on a button click. Then you could handle the array on the server side and should solve your problem.

Let me know if that works

reply

Samuel M.
09/28/2009 - 11:32

Hi this blog has been super helpful. I ran into it while googling and it has come in handy several times. Lately, I have been trying to implement this dynamic row addition without any luck.

My situation is exactly like yours except that I am pulling in data from the database.

When I run my app, I get an error stating that my object constructor received no arguments when expecting 6.. error # 1063. After that my grid appears with no data.

When I comment out my constructor the data loads properly, except in the Add task row I am only able to edit the column with the add task.

I am lost, the data seems to be trying to go through the constructor without success but I haven't been able to get to it using the debugger.

Any thoughts?

Thanks,
Samuel M.

reply

Samuel M.
10/12/2009 - 21:27

I reworked my code and got it working, It turns out that I didn't have to mirror my PHP class exactly (in terms of the constructor, since you can't pass more than one item when creating... well you could but this was not how I solved my issue)

So basically my php class constructor had more parameters than my flex one did.

reply

Tabman
11/09/2009 - 11:02

Did anyone faced this issue:
itemEditEnd event gets fired twice ?

reply

Dazed
11/23/2009 - 11:18

Very new to flex so I don't know if this will make any sense. I am trying to create several dynamic data grids per form and I was wondering if there is a way to handle this without hard coding in the grids? is there a property that will give me the ID for the grids that I can use in the commands i.e. @id.destroyItemEditor(); where @id would be the a variable containing the control name?

reply

KRAMERL
12/10/2009 - 14:48

Thanks for the code. I got the project to work and even added columns and changed the column names. My question: now that I've added data, how can it be saved so more rows and more data added and saved?

reply

kirankumar
05/01/2010 - 01:03

hi friends, iam new to flex, this blog is nice and reply is good, i had a task in the proj, that i get data and columns names dynamically and able to populate to the Dgrid, but the prob is ,i want to add 2 columns with contains textbox and checkbox, for each row , un able to do that dynamically , num of cols and data is unknown,intailizing grid in actionscript.
here is my code snippet:

public function showMyReport(selectedCheckBoxes:Array,
ColumnsDataList:ArrayCollection):void    {
                         
        if(selectedCheckBoxes.length!=0){
                                        selectedCheckBoxes.unshift("check");
                                }              
          reportdataGrid  =new DataGrid();
                                       
for(var j:int=0; j <selectedCheckBoxes.length ; j++){
        var repcol:DataGridColumn=new DataGridColumn();
                        repcol.width=100;
         repcol.headerText=selectedCheckBoxes[j];
         repcol.dataField=selectedCheckBoxes[j]
                       
   var repcols:Array=reportdataGrid.columns;
                        repcols.push(repcol);
                        reportdataGrid.columns=repcols;
               
                }
               
        var data:ArrayCollection=new ArrayCollection();
        var obj:Object;
        for(  var i:int=0;i<ColumnsDataList.length;i++)
                                {
                                       
var fields:Array=String(ColumnsDataList[i]).split(":;");
                                         
        obj =new Object();
         for(var j=0;j<selectedCheckBoxes.length;j++)
        {
                                               
         obj[selectedCheckBoxes[j+1]]=fields[j];
                                               
                                         }
                                       
         data.addItem(obj);
                                       
                                         
                                }
                               
                                reportdataGrid.dataProvider=data;
                               
        }                      

for the reportdatagrid i want to add checkboxes under the Check column, columnlistdata is data for the columns and selectedcolumns are the headers fro the dg
waiting for the suggetions ,
thanks kiran

reply

Anonymous
12/11/2010 - 01:18

 Public Shared Function IsNull(ByVal str As Object, Optional ByVal strDefault As String = "") As String
        If (IsNothing(str) = True) Then
            Return strDefault
        ElseIf (IsDBNull(str) = True) Then
            Return strDefault
        Else
            Return CStr(str).Trim
        End If
    End Function

reply

Mohan
12/30/2010 - 02:12

Tell how to do dynamic pagination in flex

<?xml version="1.0" encoding="utf-8"?>

1
2
3
4
5
6

reply

bobl
01/24/2011 - 09:49

is there a version of this example that works with FlashBuilder 4? (the example is exactly what I was looking for, but doesn't compile)

reply

Anonymous
03/11/2011 - 16:23

hi all

how to crate spreadsheet in flex by using datagrid?

reply

Anonymous
05/10/2011 - 00:47

hi All ...Will u plz help me i want to add an image in dynamic Datagrid grid . For Ex- like there is one column header name is EDIT and i want to add image of edit pic dinamicaly in all rows.

reply

AnonMouse
06/11/2011 - 14:43

Hi fellow Anonymous,

To add an image to a row, you need an itemRenderer for the image column like this (sorry for the ugly code listing):

<?xml version="1.0" encoding="utf-8"?>

reply

AnonMouse
06/11/2011 - 14:38

Hi your most excellent and helpful Fattest !

I was hoping you might have some insights on 'cell-aware' datagrid drag-n-drop.

I have a data grid that is built dynamically and visually by adding columns and rows via drag/drop from lists.

Once the columns and rows are added, I need to drag/drop images into cells of extant grid rows/columns, not create new rows or put into 'next available' cell of a row.

list A = Column Builder (drag/drop from list to build columns)

list B = Row Builder (drag/drop from list to build rows, with column 1 as the row label)

list C = Cell Contents (drag an image into any cell of an existing row except first column)

The DragEvent does not appear to have knowledge of dataGrid columns, only rows.

It is easy to add images to cells by using click events from the source Image list and the dataGrid, but not a good interaction design since users are drag/dropping the rest of the grid.

Will I need to create a custom DataGrid for 'cell aware' drag and drop ? if so, any pointers on where to start looking in the DataGrid code would be most appreciated.

Thanks !!!

reply

AnonMouse
06/11/2011 - 14:44

<?xml version="1.0" encoding="utf-8"?>
<s:MXDataGridItemRenderer 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.dataGridClasses.DataGridListData;
                       
                        override public function set data(value:Object):void
                        {
                                if(value != null)
                                {
                                        super.data = value;
                                        dgImage.source = value.source;
                                        var testy:String = "mookie";
                                }
                        }
                ]]>
        </fx:Script>
       
        <s:Image id="dgImage" width="160" height="160" verticalAlign="middle" horizontalAlign="left"/>

</s:MXDataGridItemRenderer>

reply

Anonymous
07/15/2011 - 01:40

great job friends.. this post ss very useful

reply

Anonymous
08/24/2011 - 08:48

in flex 4.5 how I can to add rows dinamically????
please help me???
I don't know how use itemEditorBeginning in flex 4.5 with spark datagrid....

reply

ACEOU
09/19/2011 - 14:12

How can I do this with XML as the bounded data provider. I need to display an image in the last column where there are blank rows in the dataGrid. Here is my mxml xode:

For example, when an image is found in the XML from "imageURL" (last column) is displays it. I need to fill in the rest of the column's blank rows to show an image that say's "No Image" or "Add Image". This XML is loaded from the server, so I can't modify it in Flex.

reply

ACEOU
09/19/2011 - 14:13

Sorry, code here:

<mx:DataGrid dataProvider="{this._xml.sponsor}"
                id="grid"
                width="100%"
                editable="true"
                itemEditEnd="onItemEditEnd(event)"
                color="#000000">
        <mx:columns>
            <mx:DataGridColumn width="30"
                              dataField="@id"
                              headerText="ID"
                              visible="false" />
            <mx:DataGridColumn dataField="@name"
                              headerText="Sponsor Name" />
            <mx:DataGridColumn dataField="sponsorText"
                              headerText="Text" />
            <mx:DataGridColumn dataField="linkURL"
                              headerText="Link URL" />
            <mx:DataGridColumn width="80"
                              dataField="imageURL"
                              headerText="Image"
                              visible="false" />
            <mx:DataGridColumn id="sponsorImage"
                              width="70"
                              dataField="imageURL"
                              headerText="Image"
                              color="#FFFFFF">
                <mx:itemRenderer>
                    <mx:Component>
                        <mx:Image horizontalAlign="center"
                                 height="100%"
                                 width="100%"
                                 buttonMode="true"
                                 click="outerDocument.openBrowserBtnClicked()">
                        </mx:Image>
                    </mx:Component>
                </mx:itemRenderer>
            </mx:DataGridColumn>
        </mx:columns>
    </mx:DataGrid>

reply

dsreiluke
09/19/2011 - 22:20

thank you, your tutorials are the best you can find online

reply

B Chawla
10/07/2011 - 12:23

How do we specify color of newly added rows.

Suppose I have a datagrid with 4 rows. Suppose I want to add 2 more rows at index 1. The color of newly added rows should be red.

Can this be done in Flex Datagrid or any other component or any other way?

Any help will be highly appreciated. This is pretty urgent for me.

reply

Don Mitchinson
11/04/2011 - 12:08

Excellent article and example.
I couldn't find anything that made sense in any book I read. Your example and code were perfect

Thanks

reply

Nagabhushan
12/09/2011 - 06:16

This blog was of great help. I wanted to figure out a way to validate the entered text on changing focus, is there a way?

reply

richievc
12/12/2011 - 14:26

Hi Friend

Great example

works great on its own but when I start adding other components like other text Inputs it stops working I think it a conflict of versions I,m using Flex 4.5 so the data grid feature are depreciated so you have to use the mx version of the grid this causes the Text Inputs to clash is there a new version or how can we get this to work with the spark components.

Hope this makes sense .

Thanks in advance

reply

Bonnie
12/15/2011 - 11:52

Hi Fattest,

Can you please provide the code to disable auto-sorting?
I want the sort to work only when the user clicks the column headers, not when new rows are added or when a value is edited.

Thanks!

reply

snreddy
01/21/2012 - 10:06

This articel was of great help

http://sharepointsolution2010.blogspot.com/2012/01/situation-silverlight-datagrid-to-given.html

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.