The amazing adventures of Doug Hughes

NOTE: In the comments below, someone named Chris left a note about using the doubleClickEnabled attribute of the DataGrid to accomplish the same thing I did by using the initialize event and the itemRenderer. I took Chris’s suggestion and applied it to my application and it does in fact accomplish the same thing, so there’s a simpler way to deal with the problem. I would imagine that, internally, they’re roughly equivalent and, while there’s a more straightforward solution it’s nice to know why things work, which is as much what this post is about as it is what to do to get it working in the first place.

No matter which approach you take to solving the problem, this is, hopefully, the last time someone will have to take hours to find the solution… ]It would seem to me that in the past 2 years I’d have had to make a Flex DataGrid respond to double-clicks on the rows, but apparently I haven’t, because over the weekend I was working on a project and had to do just that. Since it proved to be poorly documented (at least according to my Googling) and took me quite a while to work out, I figured I’d blog what I did to make it work.

It all started with a DataGrid, and the itemDoubleClick event handler…You see, the Flex 3 DataGrid component has a built-in event handler to deal with double-clicks on its rows, but (and this I found referenced a LOT in Google searches on the subject) even though you’ve implemented it, nothing happens. This is because the rows (which are instances of a subclass of InteractiveObject) have double-click support, but it’s disabled by default. So you have to turn it on for each row in the grid… but the question is HOW?

Because the rows are all held in the DataGrid.rendererArray (which isn’t even documented!!) which is read-only, the creation of the rows is hidden behind closed doors in the DataGrid itself, and the particular classes used by this process are effectively hard-coded into the DataGrid, how on earth do you turn doubleClickEnabled on in the first place?? The answer, it turns out, is fairly simple (or blowin’ in the wind, depending on your iTunes playlist for a Monday morning)… you use the DataGrid’s itemRenderer property to apply doubleClickEnabled to each object that it creates.

Let me explain. DataGrid.itemRenderer is actually an instance of ContextualObjectFactory, which in turn has it’s own property called, of all things, “properties”. By default, it’s null, but if you add name/value pairs to it (by assigning it an instance of Object), each name/value pair is copied into every object created by the factory. So all you have to do is something like this:

<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
width="400"
height="300"
title="DataGrid DoubleClick Example">
<![CDATA[
        import mx.collections.ArrayCollection;
        private var data: ArrayCollection = new ArrayCollection();
        [Bindable]
        private function get dataProvider() {
            if (data.length < 1) {
                data.addItem({
                    Column1: "This is the first row",
                    Column2: "This is row 1 column 2 ",
                    Column3: "column 3 from row 1 "
                });
                data.addItem({
                    Column1: "This is the second row",
                    Column2: "This is row 2 column 2 ",
                    Column3: "column 3 from row 2 "
                });
            }
            return data;
        }
        private function doubleClickHandler(event: ListEvent): void {
            mx.controls.Alert.show("Column1 is: " + event.itemRenderer.data.Column1);
        }
        private function gridInit(event: FlexEvent): void {
            event.currentTarget.itemRenderer.properties = {
                doubleClickEnabled: true
            };
        }
]]>
<mx:DataGrid id="myGrid" left="10" top="108" bottom="10" right="10" dataProvider="{dataProvider}" itemDoubleClick="doubleClickHandler(event);" initialize="gridInit(event);">

First off, check out the gridInit() method, where I’m assigning event.currentTarget.itemRenderer an object with the name/value pair I want to end up on all my grid rows. Since the initialize hander is on the grid, currentTarget is the grid itself and I can work with all it’s properties as though I were using this.myGrid. I have come to love the Flex built-in events a lot. They’re not perfect, but most excellent nonetheless.Let me hit the hight points for you:

Using the initialize event on the DataGrid component to apply an object to the intemRenderer property means that the itemRenderer exists but hasn’t done anything yet, so that you don’t get any errors or omissions as happened when I was trying to do this in the parent component’s creationComplete handler, in the DataGrid’s creationComplete handler, and anywhere else I tried to add the object to the itemRenderer’s properties collection. If you do it with the parent’s creationComplete handler, it blows up with compiler errors referring to class casting from IFactory, and if you do it from the grid’s creationComplete event you get no errors but only a few of the rows are actually double-clickable. Very odd, but using initialize on the grid itself works just fine.

Setting itemRenderer.properties to {doubleClickEnabled:true} means that every object created by the itemRenderer will have doubleClickEnabled=true applied to it as part of the object creation process. Since the factory exists to create all the rows in the grid, every row will have double-click turned on and since the itemDoubleClick event has a defined handler, that handler will be called when any row is enabled.

One more bit of niftiness: When you double click a row, the ListEvent that gets fired has an itemRenderer property, which is the actual itemRenderer you double-clicked on. It has a data property, which represents the entire item from the dataProvider. An example of where this is nice is in the case of AIR, working with a DataGrid that’s populated from a query against a local database. Say your query has 10 columns, but your DataGrid’s DataGridRow tags are only configured to deal with 3 of them. The itemRenderer.data property actually contains the entire row from the query (which is actually an ArrayCollection), and the itemRenderer.listData is actually the individual cell in the DataGrid that you double-clicked on. I actually like the fact that you have access to the whole row from the original dataset.

So the next time you have to make the rows in a grid accept double-clicks and you go googling for it, I hope this comes up. This article would have saved me a few hours over the weekend. Who knows? Maybe it’ll be another 2 years before I have to do this again and it’ll save me another couple hours when I go Googling for it myself!

Comments on: "Double-click your Flex DataGrid rows" (15)

  1. Maybe I am missing the point here, but why not just use the doubleClick event handler and the doubleClickEnabled property of the grid itself?

    In the handler you then simply use the selectedItem of the grid.

    private function dblClickHandler():void
    {
    Alert.show(myGrid.selectedItem.Column1);
    }

    Like

  2. Jared Rypka-Hauer said:

    Chris,

    Thanks for the note… like I said, I’d never needed to do this before and I spent 4 hours trying to figure it out this morning. In the process I came across dozens of people who had the same problem and never seemed to get an answer, so the point was just to get it to work. All I ever found were references to the fact that you had to turn on double-click for InteractiveObjects and found a way to do it using the init event on the grid. To be honest I’m rather glad it happened because I learned a TON about the DataGrid object and item renderers in general.

    So hopefully this blog post has just become even more useful for folks in the future, and I just learned something! All the better. 😀 Thanks again!

    Like

  3. I had the very same problem a month ago. It’s really easy to solve, but takes time to find out what is going on.
    Hope this helps other people not to get lost with this issue.

    Like

  4. Jared Rypka-Hauer said:

    Cool Rodrigo… that’s it exactly.

    I also think it’s cool how this highlights how many different ways there are to do things with Flex, and the fact that you can burrow down into the object model of these components and work with their innards. It really comes down to knowing the API of the classes in the SDK, both MXML and AS, and how you can leverage any of them to your requirements.

    Like

  5. Jared Rypka-Hauer said:

    sweet… I just googled “Flex DataGrid double click” and this blog post is the second main entry in the result. Hopefully this means that other folks don’t have the same problem and can’t find a fix for it!

    Like

  6. Hi guys,

    This post was really useful for me, just today i needed implement this feature on our flex application!!

    Nice idea Chris, but you must to verify the selectedItem (different to NULL), or it can give you a error when you make double click on a empty space, without a row selected.

    anyway, Jared great approach!

    Like

  7. Jared Rypka-Hauer said:

    Something that just occurred to me now is the fact that while using the enableDoubleClick attribute works to enable double-click support on the items in the grid, using the itemRenderer approach lets you add any number of random properties to every cell in the grid. Allows you to apply any name/value pair to the items in the grid, in fact, and the values supplied can be of about any kind. So if you use this approach to enable double-click support, you can pass objects, strings, dates, whatever you want, along with it and then those values are available to you when the double-click event is fired.

    Glad it helped, SD! I was hoping it would hit Google fast and start answering this common and poorly documented problem.

    Like

  8. by other side using the itemRendered approach really we are giving to each row an event, the other approach manages a doubleClick event on the active area of dataGrid, so it works in a similar way, but not exactly the same.

    everyone will choose which is better for their case.

    Like

  9. Thanks a lot; you saved me a few hours probably. I ended up using Chris’ method.. nevertheless.

    Like

  10. Marcuski said:

    http://concealer.mybrute.com
    Check out this cool mini fighting game

    Like

  11. this article is still very valuable in 2009. thanks guy.

    Like

  12. to help me in my Tasks .

    Like

  13. Please let me know if you’re looking for a article author for your weblog. You have some really great posts and I think I would be a good asset. If you ever want to take some of the load off, I’d love to write some material for your blog in exchange for a link back to mine. Please send me an e-mail if interested. Many thanks!

    Like

  14. Hi! Once i originally commented I clicked the -Notify me when new comments are added- checkbox and now each time a comment is added I recieve four emails with the same comment. Can there be any way it is possible to remove me from that service? Thanks!

    Like

Comments are closed.

Tag Cloud

%d bloggers like this: