Flex 2.0 Tree with Spring Loaded Folders

January 25, 2007

Although the techniques described here can be applied in other ways, and on other components; one of the most practical is the tree control.

When dragging items in a Flex application the user is mouse blocked. The left mouse button is used to initiate, and keep alive the drag operation. The tree control being comprised of folders and items posses a particular problem. If the user wishes to drag the items into a closed folder, the user would have to first open the desired destination folder, then perform the drag operation. 

The Mac OSX has a really good implementation of the technique. I’m quite sure that it’s been around for some time. Here is a little blog post on the Mac version of this with a video. Apparently it was one of the most requested features users wanted back.

“according to Apple, spring-loaded folders were requested more by end users than any other missing feature. So, they brought them back in Jaguar.”

Though this implementation does not resemble the Mac OS version, they do share certain traits. I did ponder over the name “Spring Loaded Folders”, and in the end decided to stick with it. After all, it is kind of springy.

A Felx Spring Loaded Folder implementation:

When the user is dragging items, certain assumptions can be made about how to best help the user complete their task. By implementing a delayed timer, we can after a set period open the folder the user is hovering over allowing the user to complete their task.

However if the user opens a folder by hovering over it, it still may not be the folder they wish to drop the item into. As the user moves in and out of folders they are automatically opened or closed depending on certain criteria.

I store a copy of the open items before the drag start, so that the original state can be restored later. This original state is restored on drag exit and drag complete. I also compare the original open items during the close/open calls so that nodes triggered to open, will cross check with the original state in order to keep the original state intact.

Using the spacebar while dragging over a closed node will immediately open it, and cancel any timer.

I’ve added a opening indication. The opening indication will fade in and out the tree item renderer while the timer is running.

Here is a list of added properties.

  • autoCloseOpenNodes
  • autoCloseOnDrop
  • autoCloseOnExit
  • showOpeningIndication
  • autoOpenTimerMS
  • autoCloseTimerMS

Some of the difficulties I ran into:

The tree control is set up to allow only one opening or closing animation at a time. If we try to close/open multiple folders at the same time one blocks the other. However by using the ITEM_OPEN and ITEM_CLOSE tree events, and walking the close stack one at a time, I was able to set this up recursively.

The drag over event is not dispatched when you move into a node, rather into and around it. This causes problems as it’s dispatched many, many times even when moving over the same node. I tried my best to compare the current and last node so that the actions could be minimized, and only dispatch the delay open/close when the criteria is acceptable.

Closing a folder with animation when that folder has no children exposes a bug in flex. So if the node has no children I set the animate on the expandItem call to false. There was no visible way around this, and if it’s empty there was no real reason to show an animation anyway.

Conclusion:

You’ll have a better experience when opening nodes moving in an upward direction. Moving downward displaces the dragging over location when the nodes above it close. So you may want to tweak it so that it only auto opens the nodes, and restores the state on exit and complete, as opposed to auto open and auto close.

I tried several different animation effects on the open indication and decided that fade was suitable (simple is better). This is very easy to change so have at it.

The delayed timer class included can be used in many places to achieve similar effects when dragging. Dragging data grid items between tab navigator tabs for example. I’m hoping that Michael Schmalle will think about this technique for his up coming MDI components.

The sample is using a XMLListCollection as the data provider for the tree. I haven’t tested any other provider types, and tried to limit the use of xml to only @isBranch.

With a couple of really simple modifications this should work with other data providers.

If you find good places to use this technique, your users will love you for it. Tweak, modify, and extend to your hearts content.

Ideas and feedback ?

Edit : A nasty framework bug was discovered and corrected. Sample and source have been updated. I’ve created a new post describing the bug. Turns out it’s a good one to remember.

Requires Flash 9.

Sample and Source: Spring Loaded Folders

Jason Hawryluk

Advertisements

15 Responses to “Flex 2.0 Tree with Spring Loaded Folders”

  1. Ben Says:

    Very nice. Great work.


  2. Hey, 😉

    Nice to see someone looks at my blog.

    With the MDI, you are talking about when you are dragging a tab? I understand your technique here but you want to elaborate on what I might do?

    I have an idea, just clarification.

    Peace, Mike


  3. Hey Mike,

    I was thinking about opening the windows/tabs when dragged into if it’s minimized for example. Basically apply the same type of thing on any component that can be dragged into that may not be accessible/open etc..

  4. David Says:

    Small ooops:

    TypeError: Error #1009:

    Deleted : Caused formatting problem on blog.


  5. Hmmm…

    I guess I will have to have you as a beta tester Jason.

    Give me an email.

    Peace, Mike


  6. David ,

    This is the bug popping up when a child has no nodes and you try to close it in code. It’s kind of frustrating as it only happens sometimes, and hard to pin point. I’ve updated the source with another version. I’ve added better error control to try to eliminate it.

    in tree.as within the function

    buildUpCollectionEvents

    these 2 lines

    var children:ICollectionView = getChildren(expandedItem, iterator.view);
    var cursor:IViewCursor = children.createCursor();

    When the expanded item has no children.

    If anyone sees a solution to this I’d be grateful to hear about it.

    For now I’ve changed the source xml, I’ll post a fix when I’ve found it.

    jason


  7. Bug is fixed and the xml data source is as it was.

    jason


  8. […] is a link to the original post.  Sample and Source: Spring Loaded […]

  9. James Ward Says:

    What is the license of this component? Thanks!


  10. james,

    Everything you, the rest of Flex community, and generally the rest of the world find on my blog is free to use, cut apart, extend, distribute etc.. to your hearts content.

    If the community can learn and benefit from it then I’m all the happier.

    Thanks for asking though.

    cheers

    Jason

  11. judah Says:

    Nice work! I like the drag separator lines and auto opening and closing.

  12. Jeff Says:

    Hi Jason
    Great stuff, thanks for contributing!
    -Jeff


  13. […] Spring Loaded Folders: (Jason.Hawryluk@3gcomm.fr) […]

  14. Dany Says:

    Many thanks. This is a great class. Is this thread still open for any questions?
    dd

  15. Tariq Says:

    Hi
    I am new to flex. Your solution is really great and helped me to save lot of my time. I need to update the xml file structure as and when I re arrange the items in the list. how can I do that? Please help…

    Thanks


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: