Expanding nodes in a Flex Tree control using the openItems property

The following example shows how you can open nodes in a Tree control in Flex by setting the openItems property to an XMLList or Array object.

Full code after the jump.

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/01/15/expanding-nodes-in-a-flex-tree-control-using-the-openitems-property/ -->
<mx:Application name="Tree_openItems_test"
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">
 
    <mx:Script>
        <![CDATA[
            private function openAllNodes():void {
                tree.openItems = dp..node;
            }
 
            private function closeAllNodes():void {
                tree.openItems = [];
            }
        ]]>
    </mx:Script>
 
    <mx:XML id="dp">
        <root>
            <node label="Parent 1">
                <node label="Child 1" />
                <node label="Child 2">
                    <node label="Grandchild 1" />
                    <node label="Grandchild 2" />
                </node>
                <node label="Child 3" />
                <node label="Child 4" />
            </node>
        </root>
    </mx:XML>
 
    <mx:ApplicationControlBar dock="true">
        <mx:Button label="Open all nodes" click="openAllNodes();" />
        <mx:Button label="Close all nodes" click="closeAllNodes();" />
    </mx:ApplicationControlBar>
 
    <mx:Tree id="tree"
            dataProvider="{dp}"
            showRoot="false"
            labelField="@label"
            width="200" />
 
</mx:Application>

View source is enabled in the following example.

You can tweak the previous E4X statement by only returning nodes that have children: dp..node.(children().length() > 0);.

The following example uses a bit more of a complex E4X statement to find data provider XML nodes with a specific attribute, “isOpen”, and only opens those nodes.

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/01/15/expanding-nodes-in-a-flex-tree-control-using-the-openitems-property/ -->
<mx:Application name="Tree_openItems_test"
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">
 
    <mx:Script>
        <![CDATA[
            private function openSomeNodes():void {
                var xList:XMLList = dp..node.(hasOwnProperty("@isOpen") && @isOpen == "true");
                tree.openItems = xList;
            }
 
            private function closeAllNodes():void {
                tree.openItems = [];
            }
        ]]>
    </mx:Script>
 
    <mx:XML id="dp">
        <root>
            <node label="Parent 1" isOpen="true">
                <node label="Child 1" />
                <node label="Child 2">
                    <node label="Grandchild 1" />
                    <node label="Grandchild 2" />
                </node>
                <node label="Child 3" />
                <node label="Child 4" isOpen="true">
                    <node label="Grandchild 3">
                        <node label="Great-grandchild 1" />
                        <node label="Great-grandchild 2" />
                        <node label="Great-grandchild 3" />
                        <node label="Great-grandchild 4">
                            <node label="Great-great-grandchild 1" />
                        </node>
                        <node label="Grandchild 1" />
                    </node>
                    <node label="Grandchild 4" />
                </node>
                <node label="Child 5" />
            </node>
        </root>
    </mx:XML>
 
    <mx:ApplicationControlBar dock="true">
        <mx:Button label="Open some nodes" click="openSomeNodes();" />
        <mx:Button label="Close all nodes" click="closeAllNodes();" />
    </mx:ApplicationControlBar>
 
    <mx:Tree id="tree"
            dataProvider="{dp}"
            showRoot="false"
            labelField="@label"
            width="300" />
 
</mx:Application>

View source is enabled in the following example.

15 thoughts on “Expanding nodes in a Flex Tree control using the openItems property

  1. Hi Peter, Firt of all. Congratulations for the blog. It´s one of the best Fex Resources i found.

    Lets talk about this post and see if you or other reader can help me.

    Imagine that my tree is embedded into a panel. (You can see my flex page about sanish accounting software in this comment link. Section “El Plan de Cuentas)

    If i use your system to open all nodes, the content of the tree will go own from the content of the panl, but the panel is not showing me the scroll bar. Otherwise, expanding tree nodes 1 by 1 the panel show the scrolling bar when the size is not enough.

    Thanks and great Job!

  2. Luis,

    I can’t seem to reproduce the issue. Using the code from the code from the example above (second example, the first example doesn’t have enough data to cause scroll bars to appear), the scrollbars are displaying when I expand the nodes. I even created a bigger data set (code below) and the scrollbars appear correctly also.

    Also, you could try explicitly setting the verticalScrollPolicy property to “on” for the Tree and see if that fixes the issue.

    I’m using Flex 3 SDK Version 191831. Are you using Flex 2.0.1 or the Flex 3 beta?

    If you think it is a bug, can you file a bug report at http://bugs.adobe.com/flex/ and include your source code (or a simple test case showing the behavior) and myself or somebody else can take a look at it.

    Thanks,
    Peter

    <?xml version="1.0" encoding="utf-8"?>
    <!-- http://blog.flexexamples.com/2008/01/15/expanding-nodes-in-a-flex-tree-control-using-the-openitems-property/ -->
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white">
     
        <mx:Script>
            <![CDATA[
                import mx.utils.ObjectUtil;
     
                private function openAll():void {
                    var items:XMLList = xmlDP..node.(children().length() > 0);
                    tree.openItems = items;
                }
     
                private function closeAll():void {
                    tree.openItems = [];
                }
            ]]>
        </mx:Script>
     
        <mx:XML id="xmlDP">
            <root>
                <node label="American League">
                    <node label="West">
                        <node label="Los Angeles" />
                        <node label="Seattle" />
                        <node label="Oakland" />
                        <node label="Texas" />
                    </node>
                    <node label="Central">
                        <node label="Cleveland" />
                        <node label="Detroit" />
                        <node label="Minnesota" />
                        <node label="Chicago" />
                        <node label="Kansas City" />
                    </node>
                    <node label="East">
                        <node label="Boston" />
                        <node label="New York" />
                        <node label="Toronto" />
                        <node label="Baltimore" />
                        <node label="Tampa Bay" />
                    </node>
                </node>
                <node label="National League">
                    <node label="West">
                        <node label="Arizona" />
                        <node label="Colorado" />
                        <node label="San Diego" />
                        <node label="Los Angeles" />
                        <node label="San Francisco" />
                    </node>
                    <node label="Central">
                        <node label="Chicago" />
                        <node label="Milwaukee" />
                        <node label="St. Louis" />
                        <node label="Houston" />
                        <node label="Cincinnati" />
                        <node label="Pittsburgh" />
                    </node>
                    <node label="East">
                        <node label="Philadelphia" />
                        <node label="New York" />
                        <node label="Atlanta" />
                        <node label="Washington" />
                        <node label="Florida" />
                    </node>
                </node>
            </root>
        </mx:XML>
     
        <mx:ApplicationControlBar dock="true">
            <mx:Button label="Open all" click="openAll();" />
            <mx:Button label="Close All" click="closeAll();" />
        </mx:ApplicationControlBar>
     
        <mx:Tree id="tree"
                dataProvider="{xmlDP}"
                labelField="@label"
                showRoot="false"
                width="300"
                height="100%"
                verticalScrollPolicy="auto" />
     
    </mx:Application>
  3. Hi Peter.

    Are you sure that this last code of your response is working? When i copy into my Flex Builder 3 (Milestone 3 Beta 2) and execute it via Internet Explorer, if i click “Open All” button, Washington and Florida dont show and the scrollbars also dont show, so you have reproduced my problem perfectly with this example!!

    I can´t find a solution for now. I also set the verticalScrollPolicy to “on” but dont work. If i can find a solution, ill tell you.

    Thanks and sorry for my poor english

    Luis Alcalá

  4. Peter,
    In this statement,

    var xList:XMLList = dp..node.(hasOwnProperty("@isOpen") &amp;&amp; @isOpen == "true")

    you use the ‘..’ e4x operator to look for node elements with @isOpen attribute and @isOpen is true.

    If your XML elements were not but a collection with different localnames, how could you find all elements with @isOpen attributes

    var xList:XMLList = dp..(hasOwnProperty("@isOpen") &amp;&amp; @isOpen == "true")

    doesn’t compile. I’ve tried all sorts of things but can’t figure out the e4x equivalent to xpath’s ‘//*[@attr]‘

    Thanks,
    Craig

  5. It seems in Flex SDK 2.0.1, the vertical scrollbar will not be updated when the openItems is changed. Does anyone know how to fix this?

    You can reproduce the problem by just compile the second sample in Flex SDK 2.0.1 and click “Open some nodes”, and the vertical scrollbar will not show!

  6. hello all,

    first of all a big respect for this blog.

    Got also problems with the vertical scrolling….

    Here is nice tutorial for a tree with amfPHP (http://www.sephiroth.it/tutorials/fl…fphp/index.php)

    i’ve used it for my app, but running into some trouble now, with the scrollbars, what i really didn’t expect!!

    here you can see the app and the source code:
    http://www.rootop.de/testing/TestTree.html

    it’s all german, so when you click on Enomis -> Einzelstoffe->Obst , then there appears a scrollbar for a short time and then disappears again, even if there are more branches… it really makes me mad.. i tried serveral function like..

    //scroll always to bottom, otherwise, only the items are shown, that are in the visible area
    tree.verticalScrollPosition=tree.maxVerticalScroll Position;

    tree.invalidateList();

    tree.validateNow();

    but nothing really works. the general problem is, that i don’t know when flex display the scrollbar and when not. because in some cases it works.
    so, if there is a solution or a workaround, i would be very happy. thanks in advance. kind regards, peter

  7. I have a tree that the dataprovider changes, and using methods such as tree.openItems = tree.dataProvider; would open only the top level, and tree.dataProvider().descendants(); would open everything EXCEPT the top level. what I finally came up with is tree.openItems = tree.dataProvider[0].parent().descendants(); and that opens everything.

  8. Thanks for the example. I have a case that I haven’t really found a good solution to so I came up with a bit of a hack.

    I would include the source, but I keep getting a spam error. Sorry.

    I needed an event to fire when the dataGrid.selectedItem changed. I tried a change event on the grid, but the expandChildren method didn’t seem to take. The added Event seemed to be the only way I could update the data at the right time to get the tree to expand.

    If you think of anything to clean up this mess of a code I’d love to hear about it!

  9. Jason, as soon as I posted, I read your response and tried it in the change event of my dataGrid. It worked like a charm and it’s way more efficient. Thanks!

  10. Hi,
    I am new to flex and am facing the a problem with flex tree ,it is not displaying all the node when an ever fires .. here is my scenario

    we have two flex tree..one is Left side tree and other is right side treee .I call the left tree as ltree and right tree as rtree. I am using the object as the data provider for both the trees. ltree has the lot of nodes and each node’s data has an Object with its properties. If we click on any node of the ltree,i have to display the rtee with all the properties of the ltree node. So i am getting the object from ltree and creating the root node of rtree and assiging it as the dataprovider to rtree . rtree data provider need to change faster as soon as evvent fires on ltree node.I just assigned the rtree’s data provider and rtree is displaying the contents,but the problem is rtree nodes/childs are not displaying properly .when expand any node of the rtree only few child nodes display once and few display secondtime. so the display is not consistent.i am doing all the things after updating the dataprovider like invalidateDisplayList,validateNow on rtree as well as the panel that contains rtree.but no luck..here is my bit of sample code

    package actionscript.shmtool.tree
    {
    	import mx.collections.ArrayCollection;
    	[Bindable]
    	public class TreeNode
    	{
    		public function TreeNode()
    		{
    		}
    		public var type:String="";
     
    		public var name:String="";
    		public var isLeaf:Boolean;
    		public var children:ArrayCollection;
    		public var parentNode:DataTreeNode;
    		public var dataObject:Object;
    		public function addChild(child:DataTreeNode):void{
    			if (this.children == null)  
    					 this.children = new ArrayCollection(); 
     
    			children.addItem(child);	
    		}
    	}
    }

    and on the selection of ltree node,i am doing the below

    var configRootNode:DataTreeNode= commonUtils.getConfigTreeNode(selectedNode);
    configurationTree.invalidateList();
    configurationTree.dataProvider=configRootNode;
    configurationTree.validateNow();
    configurationTree.invalidateList();
    configurationTree.invalidateDisplayList();
    configTreePanel.visible=true;

    I am reading lot of blogs that i need to set the binding to the label field,but i am not aware where and how i have to set incase if i am using objects as the data probider. Could you please assist me the solution to my problem

    Thanks
    lakjohn

  11. Hi Peter,

    Great article.
    For a Project with BlazeDS I had to work with updating and reloading Tree View Data without breaking the User Experience (all nodes closed when data reloaded).
    Instead of keeping tabs on “which node was opened before?” and “what was the scroll-position?” I found a way to inject the new state of the Tree View data into the existing data provider.

    See article here if you are interested.
    BlazeDS and Smooth Data Injection – Reloading the Tree View Data Provider without breaking the User Experience – http://bit.ly/92h7on

    Hope this is of help as well.

    Peter

Comments are closed.