05
Apr
08

Opening branches by clicking rows in a Tree control in Flex

The following example shows how you can expand/collapse branches in a Flex Tree control by clicking on the row instead of having to click on the disclosure/arrow icon.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/04/05/opening-branches-by-clicking-rows-in-a-tree-control-in-flex/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            import mx.collections.ICollectionView;
            import mx.events.ListEvent;

            private function tree_itemClick(evt:ListEvent):void {
                var item:Object = Tree(evt.currentTarget).selectedItem;
                if (tree.dataDescriptor.isBranch(item)) {
                    tree.expandItem(item, !tree.isItemOpen(item), true);
                }
            }

            private function tree_labelFunc(item:XML):String {
                var children:ICollectionView;
                var suffix:String = "";
                if (tree.dataDescriptor.isBranch(item)) {
                    children = tree.dataDescriptor.getChildren(item);
                    suffix = " (" + children.length + ")";
                }
                return item[tree.labelField] + suffix;
            }
        ]]>
    </mx:Script>

    <mx:XML id="dp">
        <root>
            <folder label="One">
                <folder label="One.A">
                    <item label="One.A.1" />
                    <item label="One.A.2" />
                    <item label="One.A.3" />
                    <item label="One.A.4" />
                    <item label="One.A.5" />
                </folder>
                <item label="One.1" />
                <item label="One.2" />
            </folder>
            <folder label="Two">
                <item label="Two.1" />
                <folder label="Two.A">
                    <item label="Two.A.1" />
                    <item label="Two.A.2" />
                </folder>
            </folder>
        </root>
    </mx:XML>

    <mx:Tree id="tree"
            dataProvider="{dp}"
            showRoot="false"
            labelField="@label"
            labelFunction="tree_labelFunc"
            width="300"
            rowCount="6"
            itemClick="tree_itemClick(event);" />

</mx:Application>

View source is enabled in the following example.


21 Responses to “Opening branches by clicking rows in a Tree control in Flex”


  1. 1 eternalko Apr 5th, 2008 at 11:09 am

    Hi Peter!!!

    This is what I was looking for!!!

    THANK YOU!!

    eternalko

  2. 2 Klaus Busse Apr 6th, 2008 at 2:36 am

    Hi Peter,

    great and very useful :-)

    Klaus

  3. 3 coco Apr 7th, 2008 at 6:42 pm

    thanks,good example!

  4. 4 Yair Apr 9th, 2008 at 3:07 am

    How do I translate this example to use in an advanceddatagrid?

    Thanks,
    Yair

  5. 5 Xyrer Apr 9th, 2008 at 9:12 am

    You amaze me with every post, thanks a lot.

  6. 6 James Apr 14th, 2008 at 12:21 pm

    OMG have been trying to find this for ever. Would be nice to see a XML populate this navigation with subcategories, would be killer!

  7. 7 lwz7512 Apr 15th, 2008 at 8:43 pm

    very useful sample, I have used it in our project!
    thanks!

  8. 8 nwebb May 22nd, 2008 at 6:26 am

    Thanks.

    Just a note - it looks like the itemOpen and itemClose events don’t get dispatched when you click on the row (only when you click on the arrow), so you may need to dispatch them manually:

    private function tree_itemClick(evt:ListEvent):void {
        var item:Object = Tree(evt.currentTarget).selectedItem;
        var eventType:String;
        if (tree.dataDescriptor.isBranch(item)){
            tree.expandItem(item, !tree.isItemOpen(item), true);
            // Clicking on anything other than the arrow doesn't dispatch the
            // normal Tree events, so manually dispatch...
            eventType = (tree.isItemOpen(item)) ? TreeEvent.ITEM_OPEN : TreeEvent.ITEM_CLOSE;
            var event:TreeEvent = new TreeEvent(eventType);
            event.item = item;
            tree.dispatchEvent(event);
        }
    }
    
  9. 9 peterd May 22nd, 2008 at 8:32 am

    nwebb,

    Great tip, thanks!

    Peter

  10. 10 Jim Thompson Jul 10th, 2008 at 2:34 pm

    Is there a way to keep the folders from getting selected with the highlight. They can highlight on rollover, just not persist the highlight on click.

  11. 11 Tom Jul 11th, 2008 at 3:22 am

    Dont work, for dispatch this event you have to use the internal function dispatchTreeEvent!

    1 - import mx.core.mx_internal;
    2 - use namespace mx_internal;
    3 - dispatchTreeEvent(TreeEvent.ITEM_OPENING,
    item, //item
    this, //renderer
    evt, //trigger
    !isItemOpen(item), //opening
    true, //animate
    true) //dispatch

    mx_internal allow to access to ‘private’ members and is very usefull (another example is for the VideoDisplay to enable the smoothing)

  12. 12 Kalpesh Jul 17th, 2008 at 5:41 am

    Is it possible to make wordwrape for TExt…Or is it possible ot make variable row height with tree control….

  13. 13 Gerry Jul 27th, 2008 at 1:38 am

    Great work!

    Could you please tell me how to handle the item_click stuff in reference to an ADVANCEDDATAGRID.

    Many thanks in advance.

    Gerry

  14. 14 Andrew Maurer Jul 31st, 2008 at 7:05 pm

    Thanks Peter, Great stuff!

  15. 15 John Aug 11th, 2008 at 9:25 am

    I’d like to see an example of this with AdvancedDataGrid as well!

  16. 16 GT Sep 8th, 2008 at 3:05 am

    Hi all.

    For those who want to apply the same logic to an ADG, here’s what I did (I’m an amateur, so be gentle if the coding turns out to contain woeful inefficiency)…

    private function adg_itemClick(evt:ListEvent):void {
        var item:Object = AdvancedDataGrid(evt.currentTarget).selectedItem;
        totList.expandItem(item, !totList.isItemOpen(item), true);
    }
    

    It worked perfectly. I got rid of the if test because I couldn’t find the adg crollary to the dataDescriptor.isBranch bizzo. (’Bizzo’ is an Australian technical term, meaning ’something I dont really understand’… I understand if you aren’t familiar with it)

    ‘totList’ is the adg to which this function is applied as an itemClick.

    As usual, flexexamples has given me something that solves a problem - with my role being to find out how to bash the example to fit my project.

    Cheerio

    GT
    France

    PS sorry for not uttingthe code in acode frame - I can’t see how to do that.

  17. 17 Lee Probert Sep 12th, 2008 at 8:23 am

    Just to confirm … with the AdvancedDataGrid not checking if the clicked item is a branch doesn’t seem to matter. The only thing that confused me is the AdvancedDataGridItemSelectEvent in FB3 that the compiler doesn’t like … you need to use a standard ListEvent … ho-hum! Also, while I’m at it … if you’re wondering how to assign different Item renderers for different branches look in the Flex help at the <mx:rendererProviders> tag … this was very handy!

  18. 18 Steven Walter Sep 26th, 2008 at 7:58 am

    Is there a way to get the actual item from a itemRollover event when using an advanced datagrid that is grouped from a flat arraycollection? With the original datagrid you could simply get the item using this method on the event:

    event.currentTarget.dataProvider.getItemAt(event.rowIndex))

  19. 19 DjKermit Oct 22nd, 2008 at 7:02 am

    About that close/open event dispatching, look at fourth parameter of expandItem method (dispatchEvent:Boolean = false). Set it to true and it will work just fine.

  20. 20 Senthil Oct 29th, 2008 at 6:04 am

    How to get the exact value from a itemRollover event when using an advanced datagrid

  21. 21 Vijay Mareddy Dec 2nd, 2008 at 7:30 am

    For ADG u need to use the ADGGroupItemRenderer:

    public class MyAdvancedDataGridGroupItemRenderer extends AdvancedDataGridGroupItemRenderer {
        private var _listOwner:AdvancedDataGrid;
        private var _listData:AdvancedDataGridListData;
    
        public function MyAdvancedDataGridGroupItemRenderer(){
            super();
        }
    
        override public function set listData(value:BaseListData):void {
            super.listData = value;
            if (value) {
                _listData = value as AdvancedDataGridListData;
                _listOwner = value.owner as AdvancedDataGrid;
    
                label.addEventListener(MouseEvent.MOUSE_OVER,
                    function(event:MouseEvent):void {
                        _listOwner.contextMenu = myContextMenu();
                        event.stopImmediatePropagation();
                    });
    
                label.addEventListener(MouseEvent.MOUSE_OUT,
                    function(event:MouseEvent):void {
                        _listOwner.contextMenu = null;
                        event.stopImmediatePropagation();
                    });
    
                addEventListener( MouseEvent.CLICK,
                    function(event:MouseEvent):void {
                        _listOwner.expandChildrenOf(_listData.item, !_listData.open);
                        event.stopImmediatePropagation();
                    });
            }
        }
    
        private function myContextMenu():ContextMenu {
            var contextMenu:ContextMenu = new ContextMenu();
            contextMenu.hideBuiltInItems();
    
            var expandCollapseItem:ContextMenuItem = new ContextMenuItem("Expand/Collapse Item",false,true,true);
            expandCollapseItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,
                function(event:ContextMenuEvent):void {
                    _listOwner.expandItem( _listData.item, !_listData.open, false, false,null);
                    event.stopImmediatePropagation();
                });
            contextMenu.customItems.push(expandCollapseItem);
    
            var expandCollapseChildrenOf:ContextMenuItem = new ContextMenuItem("Expand/Collapse Children Of",false,true,true);
            expandCollapseChildrenOf.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,
                function(event:ContextMenuEvent):void {
                    _listOwner.expandChildrenOf(_listData.item, !_listData.open);
                    event.stopImmediatePropagation();
                });
            contextMenu.customItems.push(expandCollapseChildrenOf);
            /**
             *     collapseAll/expandAll  is causing
             *     Error #1502: A script has executed for
             *     longer than the default timeout period of 15 seconds.
             */
            //            var collapseAllMenuItem:ContextMenuItem = new ContextMenuItem("Collapse All Groups",true,true,true);
            //            collapseAllMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,
            //                function(event:ContextMenuEvent):void {
            //                    _listOwner.collapseAll();
            //                });
            //            contextMenu.customItems.push(collapseAllMenuItem);
            //
            //            var expandAllMenuItem:ContextMenuItem = new ContextMenuItem("Expand All Groups",false,true,true);
            //            expandAllMenuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,
            //                function(event:ContextMenuEvent):void {
            //                    _listOwner.expandAll();
            //                });
            //            contextMenu.customItems.push(expandAllMenuItem);
    
            return contextMenu;
        }
    

Leave a Reply

This blog is terrible at eating HTML tags. If you plan on posting code/XML, please escape your "<" characters as "&lt;" and your ">" characters as "&gt;".




Badge Farm

  • Firefox 2
  • Powered by Redoable 1.2
  • Feeds burnt by Feedburner
  • Feed