Yesterday, while working on a Flex project, I had to significantly alter how I was using a particular DataGrid in the application. Originally, this DataGrid allowed an authenticated user the opportunity to associate other users in the system with their particular project.

The process was, at the time, simple: adding a user simply meant clicking a button and editing the default information in the grid. Removing was just as easy. Select the user in the grid and press the button for remove.

However, the Web Service on the back-end was not fully designed for this feature and how it would play out in "real life". The documentation indicated that you simply pass in the grid data (converting said data to the appropriate objects for the service to process) and the Service would handle the rest.

As we flushed out this service more (this is the first project where I haven't control the server-side code...it's weird), we decided to make some good changes. The way out changes played out in the DataGrid was that I needed a way to track what users were added to or removed from the grid.

For a newly associated user, the process was easy. I added a property, named "Add", to the Value Object (VO) I use as the basis for the DataGrid. When a new user is added to the grid, I set the value of the "Add" property to "true". An existing user in the grid's value for this property was already set to "false".

But what about removing a user? If I removed them from the grid as in the previous approach (above), I was left with no simple way to track the removed user. So, I decided (in the interest of time) to add a Remove property to the VO. Not surprisingly, the Remove property defaults to "false". This property's value would be best set/unset in the grid itself...but how?

I decided to use an Item Renderer in the grid for this property and chose a checkbox (mx:CheckBox). It seemed easy enough to do this. In fact, the code to use a mx:Checkbox component as an item rendered in the DataGrid is as easy as this:












Pretty easy. However, I needed a way to dispatch an event when the checkbox was clicked/selected. Along with this event, I needed to pass the row number in the grid of the selected item so that I could properly set the Remove property to "true". The Web Service does not accept boolean values, only string, hence why I am using "true" and "false" and not actual boolean values.








--CDATA opening 'tag' removed for code sample
import com.nci.asa24.admin.control.events.ColumnSelectedEvent;
private function sendClick( evt:Event=null ):void
{
var event:ColumnSelectedEvent = new ColumnSelectedEvent( ColumnSelectedEvent.COLUMN_SELECTED, this.listData.columnIndex, this.selected );
dispatchEvent( event );
}
--CDATA closing tag removed for code sample







An important thing to note is that when you use an item renderer in this way, it runs in its own scope, unaware of what's going on in the containing component (the mx:DataGrid, etc.). This really threw me and is why you see the mx:Script block in the renderer.

Additionally, check out the listData property of "this". I never knew about this property before (the things I don't know and keep learning about Flex/AS3 constantly amaze me!). In short, it references the containing grid and its details. Very, very handy! It's also how we get the currently selected row number to use when updating our property.

You'll also notice in the code above that I imported a custom event (this event was taken from the Flex 3 Cookbook). Here's that event class, for those interested:

package com.
{
import flash.events.Event;

public class ColumnSelectedEvent extends Event
{
public var colIndex:int;
public var isSelected:Boolean;

public static const COLUMN_SELECTED:String = "ColumnSelected";

public function ColumnSelectedEvent( type:String, colIdx:int, isSelected:Boolean )
{
super(type,true,false);// note that I set bubbles (param 2) to true...this is a must!!
this.colIndex = colIdx;
this.isSelected = isSelected;

}

override public function clone():Event
{
return new ColumnSelectedEvent( type, colIndex, isSelected );
}

}
}

This event captures two key pieces of data: the currently selected row in the grid and whether or not the checkbox is selected. I'll use the later to determine the correct value to apply to the Remove property.

NOTE In the comments of the code snippet for the custom event above, I note that I set the bubbles property of the event to true. This was crucial for me. Without having the event bubble up, the listener for the DataGrid never heard the event. Do not forget to check that (bubbling property) if you are in this situation!!

In order to "hear" the checkbox being clicked, I added an event listener to the mx:DataGrid element. To do so, I assign a function to the creationComplete handler in the mx:DataGrid's attributes (creationComplete="assignListener()") that will setup the listener. That function follows:

private function assignListener():void
{
this.dg.addEventListener( ColumnSelectedEvent.COLUMN_SELECTED, removeSelected );
}

Pretty simple, really. Now, here's the "removeSelected" function that gets called when the event is captured.

private function removeSelected( evt:ColumnSelectedEvent ):void
{
if( evt.isSelected )
{
this.dg.dataProvider[evt.colIndex].Remove = "true";
}
else
{
this.dg.dataProvider[evt.colIndex].Remove = "false";
}
}

With this code in place, I am able to easily have the value of the VO's remove property set to the strings true or false.

I hope that this post can save someone (anyone, really :) ) a little time if you're in a similar position with your application.

Comments

RichieInOz
Hello,

This is a great example, very easy and the most simple I have found online.

My question is, how do you center a checkbox, using the layout in this fashion? I cannot figure out how to vertically/horizontally align my checkbox inside the datagrid column. Any ideas?
Brooks
Craig, could you show us an example. Also anyway we can get the full source instead of snippets! please help, i have this exact problem!
Craig Kaminsky
Thanks, Rasmus! I'll try that again ... it's been a while since I messed with this but recalled that I could not dispatch the event from the click handler and get the right data passed in, which was why I had the semi-kuldgy mx:Script tag. I probably missed something though :) and will check it out.

Cheers, Craig
Rasmus
cath, code is there - just view page source. seems the brackets throws off Chrome.

Thanks for the first useful implementation of a checkbox column! btw, if you want to get rid of the script block (it aint pretty), you could just fire event from click:
click="dispatchEvent(new ColumnSelectedEvent(blabla))" ...
cath
hi, is it just me or there really is no posted code for the itemRenderer?