Adding Dynamic Rows To Flex DataGrid
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. |
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.
<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.
{
[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.
<![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.
dataProvider="{tasks}"
sortableColumns="false" editable="true">
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.
<![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.
{
// 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.
{
// 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.
Posted in Flex, All Tutorials by The Fattest |

October 3rd, 2008 at 3:29 am
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.
October 3rd, 2008 at 9:48 am
No libraries are needed for this, just the code. Just download the source from http://blog.paranoidferret.com/files/Tutorials/Flex/DataGridAddRow/srcview/ or copy and paste from there.
October 12th, 2008 at 7:29 am
Great example!
thanks!
October 12th, 2008 at 7:30 am
thanks for the post! it’s excellent
October 21st, 2008 at 4:14 pm
tab key functionality is whack, i am trying to figure out how to correct that, not having much luck.
October 21st, 2008 at 7:00 pm
what are you looking to do with the tab key? I feel it works as expected.
October 22nd, 2008 at 9:36 am
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.
October 22nd, 2008 at 10:31 am
i changed the editEnd function to the following to get what I expected.
// 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
October 22nd, 2008 at 1:08 pm
Thanks for giving us an update and sharing the your code bilbo.
November 6th, 2008 at 8:36 am
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!)
November 6th, 2008 at 2:44 pm
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
November 11th, 2008 at 9:37 pm
wayne, you can use a component called a repeater to do what your looking for.