6 Replies Latest reply on Jul 4, 2010 10:14 AM by PeakDigital

    Maintaining state of Tree after refresh from server (expand open nodes)

    PeakDigital Level 1

      My current project contains a Tree that has an XMLListCollection dataProvider. The dataProvider is populated by an HTTPService, and gets refreshed from the server each time a new item is created, edited or deleted.

       

      My problem is that the Tree loses state at refresh - all nodes collapse.  From the reading I have done it appears this is a common issue.

       

      I have found references in the manual to implementing IUID, but what I am reading does not seem to apply to XML or XMLListCollection.

      http://livedocs.adobe.com/flex/3/html/help.html?content=about_dataproviders_8.html

       

      This problem has cost me many hours of frustration. Can anyone point me to a resource that can explain how to re-expand nodes in a tree that is using XML for its dataProvider instead of ArrayCollection or a custom class implementing IUID interface?

       

      I have built a recursive XML parser that gathers identifying data from each node, and then applies that list after the dataProvider is reloaded, trying to use the expandItem method. However, though it runs without errors, the nodes do not expand.  I stepped through in debug and saw it processing code refering to uid, but I cannot yet make the connection between uid and XML.

       

      Thanks for any assistance you can offer.

       

      Paul

        • 1. Re: Maintaining state of Tree after refresh from server (expand open nodes)
          pradeep reddy Level 1

          Hi Paul,

           

           

          If u want to maintain the State of the Tree then try this,,

           

                            var obj:Object = tree.openItems;

           

           

          Then assign the new dataprovider to the tree... after assigning new dataprovider then set the openItems property of the Tree...!

           

           

                             tree.openItems = obj;

           

           

          Thanks,

          Pradeep

          • 2. Re: Maintaining state of Tree after refresh from server (expand open nodes)
            PeakDigital Level 1

            Pradeep,

             

            Thank you for your suggestion. Unfortunately something in my project is preventing it from working. I had previously tried a similar method, using XMLList instead of Object to contain openItems, and neither works.  No errors appear, but nodes do not expand.

             

            Thanks again.

            Paul

            • 3. Re: Maintaining state of Tree after refresh from server (expand open nodes)
              pradeep reddy Level 1

              Hey Paul,

               

               

              Can i get some sample code...! So that i can help... and i can also learn some thing new...!

               

              Thanks,

              Pradeep

              • 4. Re: Maintaining state of Tree after refresh from server (expand open nodes)
                rootsounds Level 4

                Let's look at 2 examples from the trusty Flex Examples blog:

                 

                You can user the Tree.openItems property to pull the list, but I'm guessing that these references will not be any good once the tree's data provider is updated.

                 

                My suggestion is that you pull out the uids from the open items. Then on dataProvider update, construct a new XMLList or Array of the nodes matching your preserved uids. Now you will have a collection of references to nodes in the current dataProvider, so you just set openItems to your new XMLList/Array.

                 

                Disclaimer: I've not tested this. Just my best guess from looking at the documenation and the above examples.

                • 5. Re: Maintaining state of Tree after refresh from server (expand open nodes)
                  PeakDigital Level 1

                  Pradeep and rootsounds, thank you for replying.

                   

                  Pradeep, I can't easily provide sample code since the affected code is strewn through 5+ classes (and right now it's such a mess I'm too embarrassed to post it )

                   

                  ---

                  rootsounds, I think your suggestion is similar to what I came up with, but even with a matching XMLList, setting openItems has no effect. I also haven't had any success in extracting Flex-assigned uids from XML; I built my own for the matching XMLList from attributes in each node.

                   

                  =========================

                   

                  All,

                   

                  I am getting some strange and unpredictable behavior at this point. I suspect something to do with timing of calling invalidateList() or validateNow() though I can't be sure.  The first root node of my tree will never open, others do... sometimes.

                   

                  The current process:

                  1. Whenever a branch is expanded, set its XML attribute isOpen=true ; =false when it closes.

                  2. When user saves the tree, capture a list of all nodes with isOpen == true

                  3. Call the HTTPService to get the new Tree hierarchy

                  4. Run a recursive scan of the tree to match up the new tree hierarchy against the stored list of open nodes.

                  5. During #4 recursion, call expandItem() and validateNow() for any node that matches an item in the stored list.

                   

                  The root-level nodes sometimes do not open. as mentioned above the first node in the tree never opens. However, all child nodes seem to open properly - if I manually re-open the root node, all the nodes inside are open or closed as they should be.  Very strange.

                   

                  Thanks for your time.

                   

                  Paul

                  • 6. Re: Maintaining state of Tree after refresh from server (expand open nodes)
                    PeakDigital Level 1

                    I finally solved this using a combination of methods suggested by users here and the results of other research I did.  The following is a review of my solution, in hopes it can assist someone else in a similar situation.

                     

                    It seems there were two root causes of my issue: 1, using XMLListCollection when I should have used XMLList for the tree's dataProvider, in order to utilize e4x filtering.  2, the replacement of the dataProvider uid each time it was updated from the server.

                     

                    An example of the XML in my tree's dataProvider can be found here: http://forums.adobe.com/thread/659351 It uses several attributes, including one named isOpen. That concept was borrowed from the first resource I located when this problem arose: http://blog.flexexamples.com/2008/01/15/expanding-nodes-in-a-flex-tree-control-using-the-o penitems-property/

                     

                    The final process:

                    1. Whenever a branch is expanded, set its XML attribute isOpen=true and isOpen=false when it closes. This is accomplished via handlers for the Tree's TreeEvent.ITEM_OPEN and ITEM_CLOSE events.

                     

                    2. When user saves the tree, capture a list as an ArrayCollection of all nodes with isOpen == true  Here is the relevant code from that recursive function named testXMLdrill:

                         for each (var item:XML in theXML.theNode)
                                    {
                                    if(item.hasOwnProperty("@isBranch") && item.@isBranch == "true" )
                                        {
                                        if(item.@isOpen=="true")
                                            {
                                            _arrcollXMLDrillResults.addItem(item.@ID +"-"+ item.@Title);
                                            testXMLdrill(item);//recursive call
                                            }
                                        }
                                    }
                    

                     

                    3. Call the HTTPService to get the new Tree hierarchy

                    4. Run a recursive scan of the tree to match up the new tree hierarchy against the stored list of open nodes.

                     

                    private function detectOpenNodes(theXML:XML):void
                                {
                                if(theXML==null){return;}
                                if(_arrcollPreRefreshTreeOpenItems==null){return};
                                
                                for each (var item:XML in theXML.theNode)
                                    {
                                    if(item.hasOwnProperty("@isBranch") && item.@isBranch == "true" )
                                        {
                                        for(var i:int=0; i< _arrcollPreRefreshTreeOpenItems.length; i++)
                                            {
                                            if(_arrcollPreRefreshTreeOpenItems[i]==item.@ID +"-"+ item.@Title)
                                                {
                                                item.@isOpen="true";
                                                }
                                            }    
                                        detectOpenNodes(item);
                                        }
                                    }
                                }

                     

                     

                    5. Utilize the Tree openItems property to re-open all the branches that were previously open. This is called in the Tree's render event handler:

                     

                    this.primaryListManager.treePrimaryListManager.dataProvider=xmllistTreeData;                                
                    var xList:XMLList = xmlTreeContents..theNode.(hasOwnProperty("@isOpen") && @isOpen == "true");
                    this.primaryListManager.treePrimaryListManager.openItems = xList;                           
                                              
                    

                     

                    I hope this can prevent someone from wasting as many hours on this issue as I did.