Following on from the recent post about automatically closing the open branches of the Tree control when you open a new branch; this is a slicker implementation that does the same thing but allows you to keep the animation. Currently the Flex control falls over if you try and animate multiple branches opening or closing.
[kml_flashembed fversion="9.0.0" movie="http://blog.lyraspace.com/wp-content/uploads/2009/03/TreeExample.swf" targetclass="flashmovie" publishmethod="static" width="200" height="300"]
[/kml_flashembed]
The main thing to point out here is that this example also works if you click the Tree disclosure icon (the little triangle) as well as the item. Most of the examples out there in the blogosphere that show you how to click on items to open branches forget that the disclosure button will open/close the branch and ignore the itemClick handler you’ve setup.
I listen for the itemOpening and itemClick events and pass on to a method called handleSelectedItem. This method then checks the depth of the selected item like so.
-
var d:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(selectedItem)).listData).depth;
This looks crazy but you need to grab the itemRenderer’s listData property to find the depth of the object. It’s quite convoluted but you can grab the renderer with the Tree’s itemToItemRenderer method, cast it to the default TreeItemRenderer class and cast the listData property to the default TreeListData class to get the depth property off that … phew!
We need the depth because I only want to work with the root level branches which is level 1 in the case of a Tree. I then cycle through the Tree’s dataprovider which gives me the items in my XMLListCollection. These will correspond to the root level items as they are XML nodes with all of the children nodes (branches) in them. I can then look for siblings to the selected item using the getRoot method and close any open siblings.
-
if(tree.isItemOpen(i) && i!=selectedItem && idepth==1 && isSibling)
-
{
-
tree.addEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
tree.expandItem(i,false,true,true); // CLOSE SIBLING
-
openInstantly = false;
-
}
I create an eventListener to listen for when the open root level branch is closed and because there will ever only be one branch closing I can use animation. The openInstantly Boolean prevents the selectedItem from opening … yet. When the closed item has finished I run a short Timer delay to make sure the animation listeners are all cleared and then open the selected item.
Here’s the Application class:
-
<mx:Application
-
-
xmlns:mx="http://www.adobe.com/2006/mxml"
-
layout="absolute"
-
width="200"
-
height="300"
-
>
-
-
<mx:Script>
-
-
<![CDATA[
-
-
import mx.controls.treeClasses.TreeItemRenderer;
-
import org.osflash.thunderbolt.Logger;
-
import com.criticalmass.gucci.homepage.renderers.CustomTreeItemRenderer;
-
import mx.controls.listClasses.IListItemRenderer;
-
import mx.controls.treeClasses.TreeListData;
-
-
import mx.collections.XMLListCollection;
-
import mx.events.TreeEvent;
-
import mx.controls.Tree;
-
import mx.events.ListEvent;
-
-
private var dpx:XML = <nav>
-
-
<node label="Womens">
-
<node label="Flora by Gucci" url="assets/swf/movies/flora.swf" />
-
<node label="Gucci by Gucci" url="assets/swf/movies/gucci.swf" />
-
<node label="Classics" url="assets/swf/movies/classics.swf" >
-
<node label="Classic 1" url="http://gucci.com/class/classic1.html" />
-
<node label="Classic 2" url="http://gucci.com/class/classic1.html" />
-
<node label="Classic 3" url="http://gucci.com/class/classic1.html" />
-
</node>
-
</node>
-
-
<node label="Mens">
-
<node label="Pour Homme" url="assets/swf/movies/ph.swf" >
-
<node label="Pour Homme 1" url="http://gucci.com/ph/classic1.html" />
-
<node label="Pour Homme 2" url="http://gucci.com/ph/classic2.html" />
-
</node>
-
</node>
-
-
<node label="Boys">
-
<node label="Pour Homme" url="assets/swf/movies/ph.swf" >
-
<node label="Pour Homme 1" url="http://gucci.com/ph/classic1.html" />
-
<node label="Pour Homme 2" url="http://gucci.com/ph/classic2.html" />
-
</node>
-
</node>
-
-
</nav>;
-
-
private var dp:XMLListCollection = new XMLListCollection(dpx.children());
-
-
private var selectedItem:Object;
-
-
private var timeDelay:Timer;
-
-
//-----------------------------------------------------------------------------------
-
private function treeItemOpening(e:TreeEvent):void
-
{
-
if(!tree.isItemOpen(e.item))
-
{
-
selectedItem = e.item;
-
handleSelectedItem();
-
}
-
}
-
//-----------------------------------------------------------------------------------
-
private function treeItemClick(e:ListEvent):void
-
{
-
selectedItem = Tree(e.currentTarget).selectedItem;
-
handleSelectedItem();
-
}
-
-
//-----------------------------------------------------------------------------------
-
private function handleSelectedItem():void
-
{
-
-
var openItems:Array = tree.openItems as Array;
-
var openInstantly:Boolean = true;
-
-
var d:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(selectedItem)).listData).depth;
-
-
if(tree.dataDescriptor.isBranch(selectedItem))
-
{
-
for each (var i:Object in tree.dataProvider)
-
{
-
var idepth:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(i)).listData).depth;
-
var isSibling:Boolean = XML(getRoot(i)).@label != XML(getRoot(selectedItem)).@label;
-
if(tree.isItemOpen(i) && i!=selectedItem && idepth==1 && isSibling)
-
{
-
tree.addEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
tree.expandItem(i,false,true,true); // CLOSE SIBLING
-
openInstantly = false;
-
}
-
}
-
-
if(openInstantly) tree.expandItem(selectedItem,!tree.isItemOpen(selectedItem),true,false);
-
}
-
else
-
{
-
// Clicked on an item -- DO STUFF!
-
}
-
}
-
-
//-----------------------------------------------------------------------------------
-
/*
-
Function for accessing the Root item of the Tree
-
*/
-
private function getRoot(childObj:Object):Object
-
{
-
var parentObj:Object = tree.getParentItem(childObj);
-
if(parentObj != null) return getRoot(parentObj);
-
else return childObj;
-
}
-
-
//-----------------------------------------------------------------------------------
-
/*
-
Item closed handler
-
*/
-
private function itemClosed(e:TreeEvent):void
-
{
-
tree.removeEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
-
timeDelay = new Timer(200,1);
-
timeDelay.addEventListener(TimerEvent.TIMER_COMPLETE,openSelectedItem);
-
timeDelay.start();
-
}
-
//-----------------------------------------------------------------------------------
-
private function openSelectedItem(e:TimerEvent):void
-
{
-
timeDelay.removeEventListener(TimerEvent.TIMER_COMPLETE,openSelectedItem);
-
if(selectedItem) tree.expandItem(selectedItem,true,true,false);
-
}
-
]]>
-
</mx:Script>
-
-
<mx:Tree
-
-
id="tree"
-
width="200"
-
height="300"
-
dataProvider="{dp}"
-
labelField="@label"
-
itemClick="treeItemClick(event)"
-
itemOpening="treeItemOpening(event)"
-
/>
-
-
</mx:Application>




July 12th, 2009 at 4:41 pm
What a good example. You have just made my day.
August 31st, 2009 at 11:13 am
Brillant example, god bless you….. Amazing …. amazing …. thanks .. for posting it.
December 28th, 2009 at 11:43 am
Hi, this is a great example, I appreciate your work. I am getting some problems with this code when there is vertical scroll bar coming. If we give more data in dataprovider, lets say we give 20 nodes xml and vertical scroll bar is appearing with Tree control. The problem is when I clicked an element which will be visible once you scroll and it gives “cannot access property with null reference”. Then I started debug and found that the problem is in this line “var idepth:int = TreeListData(TreeItemRenderer(this.itemToItemRenderer(i)).listData).depth;” It gives depth to the items which are visible, it doesn’t give depth and gives errors for the tree items which are not visible. Can you guide me to fix this? I really wonder if you can give me a solution.
Thanks
KARTHIK
January 12th, 2010 at 8:22 pm
Hello, Great example, but I’m having the same problem as Karthik. If there is a solution, I’d be interesed.
Thanks, Jon
January 12th, 2010 at 8:57 pm
Hi guys. So the items outside the viewport are not registered as having a depth? Is that the issue? I will need to dig the code out and take a look at this. Seems bizarre though ay?
January 12th, 2010 at 9:00 pm
Found one potential solution:
I removed the idepth variable altogether, and replaced the if statement with the following:
if (tree.isItemOpen(i) && i != selectedItem && isSibling)
The above fixes the issue with minimizing the root nodes, however, the animation is not perfect when clicking on a node while the vertical scroll bar exists.
March 12th, 2010 at 6:18 pm
Thanks a lot.If any other to do this.please inform me in short
May 12th, 2010 at 6:04 pm
I cannot put this to work. If i just copy paste the code i have the problem with the 2 imports: import org.osflash.thunderbolt.Logger; import com.criticalmass.gucci.homepage.renderers.CustomTreeItemRenderer;
If i comment those 2, i get it working but with a strange behaviour. Cliking in a node does not close the open one and the easing funtion does not work.
Any help?
Thanks,
July 2nd, 2010 at 4:08 pm
hi! thank you so much for this example. i was getting crazy with this! you gave me new hope to complete a job that i was about to quit..
i’m sorry in advance for my horrible english and for my ignorance (i’m not a good coder.. not at all!!)
now… i can close the main sibling open branches when i click on a closed one.. and this is GREAT!! thanks!
but my question is: can we do it also on the deeper nodes and not only on the main branches?
what i’m trying to do is mainly 2 things:
1. when a main branch get closed
[ tree.expandItem(i,false,true,true); ]
..can we close also its children at the same time?
in this way, when we re-open the same main branch,the children should be always closed.
2. if i am clicking on a sub-branch (let’s say for example at depth 2), can i close its siblings at the same depth?
(in other words, i would like to do the same trick that we do on the main branches, but also on the sub-branches, at any relative depth)
do you think these two patches are possible?
can anyone please help me?
i hope my explanation was not too confused..
thank you in advance.. and thank you lee in any case for this great example!
bye.
r.