8 Replies Latest reply on Dec 29, 2007 8:41 PM by Kevin D. Wright

    Dynamic Accordion 2-Levels deep

    Kevin D. Wright
      Hello,

      I'm relatively new to FLEX and I am having a problem referencing a dynamically named UI object to add a child to.
      I am building a menu with an accordion, adding tab sections using the addChild method, and then trying to add link buttons within each tab section. No matter how I try to reference the dynamically named tab section, nothing seems to work....
      any help would be appreciated.

      A graphic of my layout can be viewed here to better understand the problem I am trying to solve.
      click here for graphic

      There are 3 panels and empty accordians (hardcoded in the mxml) ,
      I retrieve from a database a list of tabs I want to display, loop through and add to the accordian in which it belongs.

      This works up to this point and adds all the children correctly, but trying to add children (link buttons) to those newly added children (tab sections) is where I'm tripping up....


      my code follows;

      private function getSubCategoryTypes_ResultHandler(event:ResultEvent):void{

      acSubCategoryTypes = ArrayCollection(event.result);

      for ( var i:int=0; i < acSubCategoryTypes.length; i++ ) {
      var iPanel:int = acSubCategoryTypes .PanelSort;
      var iTab:int = acSubCategoryTypes
      .TabSort;
      var tabID:String = 'TB'+ iPanel + "-" + iTab;
      accordion_addChild(this['Ac'+ iPanel], acSubCategoryTypes .TabTitle, tabID)
      }
      }


      private function accordion_addChild(accordion:Accordion, childTitle:String, tabID:String):void{

      var vbox:VBox = new VBox();
      vbox.label = childTitle;
      vbox.id = tabID;
      vbox.percentWidth = 100;
      vbox.percentHeight = 100;
      accordion.addChild(vbox);

      // this is where I call the function to get the list of links I want to populate the accordian sections with.
      createLinks(childTitle); //
      }

      private function createLinks(tabName:String):void {
      RO_SecurityMenu.getLinkList(tabName);
      }

      private function getLinkList_ResultHandler(event:ResultEvent):void{
      acLinkItems = ArrayCollection(event.result);

      for (var i:int=0; i < acLinkItems.length; i++ ) {

      var urlPath:String = acLinkItems
      .URL;
      var linkLabel:String = acLinkItems .Descr;

      var iPanel:int = acLinkItems
      .PanelSort;
      var iTab:int = acLinkItems .TabSort;

      // but I cannot seem to reference it correctly when it is dynamically named.
      var vbox:VBox = this['TB'+ iPanel + "-" + iTab];

      var linkButton:LinkButton = new LinkButton ();
      linkButton.label = linkLabel;
      linkButton.id = linkLabel;
      linkButton.data = urlPath;
      linkButton.addEventListener(MouseEvent.CLICK, application.followLink);

      // if I hardcode this line to a hardcoded accordian tab section it works.....
      vbox.addChild(linkButton);
      }
      }


      I have been pulling my hair out trying to get this to work... I don't have much left!!!
      Any help would be appreciated greatly!!

      Thanks,
      Kevin
        • 1. Re: Dynamic Accordion 2-Levels deep
          buabco Level 1
          HI!

          I think you haven't created a property in the accordeon to reference the tabs so you can't call the the way you are doing it: accordeon["TABNAME"].

          I'm pretty sure that the accordeon class is not dynamic so you wont be able to add a property with the name of the tab anyway.

          So try keeping a reference to your dinamicallty created vBoxes somewhere else, prehaps in an array or in a relation array.
          • 2. Dynamic Accordion 2-Levels deep
            Kevin D. Wright Level 1
            The tabs are being created correctly and dynamiccally named also,
            I added a click event to give me the tabs ID in an alert and they are correct.

            vbox.addEventListener(MouseEvent.CLICK, application.clickTab);
            goes to this function --->
            private function clickTab(event: Object):void {
            Alert.show(event.target.id);
            }


            Its adding children to the tabs I'm having trouble with................
            • 3. Dynamic Accordion 2-Levels deep
              Garyl Woolworth Level 1
              The problem lies in calling the remote method within your for loop where VBox is added into the accordion. Everytime a VBox is added you call the function for your service and grab the appropriate items you need to add. The problem with this logic is that you are using the same result function for every call you make and your array collection gets reset everytime whether it's finished handling the items to add or not. A better way to go about this would be to add all of your VBox's like you are and store the childTitle inside of an array. Then once you have all of your accordion items that you know the link buttons you need to add (your array of childTitle's) call your remote service once and pass it this array. Then have your server side process the array and send you back your query / array of items you need to add for all of the VBox's. This means you'll only have one result event and within that result event you can run a single loop and add all of your link buttons at once. This also means you will only have to call your remote service once instead of waiting for many small queries to process with a higher chance of timeouts / delays.

              One thing to note is when setting an event result to an array collection it's expecting a(n) array as the argument so to adhere to the strict typing use acSubCategoryTypes = ArrayCollection(event.result as Array);

              Hope this gets you started in the right direction if you need more input let me know.
              • 4. Dynamic Accordion 2-Levels deep
                Kevin D. Wright Level 1
                I have moved the function call out of the loop and hooked it to a button click (just for testing)
                and on the result ------->

                private function getLinkList_ResultHandler(event:ResultEvent):void{
                acLinkItems = ArrayCollection(event.result);

                for (var i:int=0; i < acLinkItems.length; i++ ) {

                var urlPath:String = acLinkItems .URL;
                var linkLabel:String = acLinkItems
                .Descr;
                var iPanel:int = acLinkItems .PanelSort;
                var iTab:int = acLinkItems
                .TabSort;

                addLinkItem(this['TB'+ iPanel + "-" + iTab], linkLabel, urlPath)
                }
                }


                private function addLinkItem(currTab:VBox, linkLabel:String, urlPath:String):void{

                var linkButton:LinkButton = new LinkButton ();
                linkButton.label = linkLabel;
                linkButton.id = linkLabel;
                linkButton.data = urlPath;
                linkButton.addEventListener(MouseEvent.CLICK, application.followLink);

                currTab.addChild(linkButton);
                }

                Still same results....

                When I hard code a vbox (named 'KDW') in one of the accordions (in MXML)
                and change "currTab.addChild(linkButton);" to "KDW.addChild(linkButton);"
                it populates all my linkbuttons in that tab section......

                Am I referencing the dynamic name correctly??

                addLinkItem(this['TB'+ iPanel + "-" + iTab], linkLabel, urlPath)


                this seems correct to me because this is how I am already adding the tabs as children;

                accordion_addChild(this['Ac'+ iPanel], acSubCategoryTypes .TabName, tabName)
                • 5. Re: Dynamic Accordion 2-Levels deep
                  Kevin D. Wright Level 1
                  It works also when I pass 'KDW' as the vbox into the function, so I know the function is declared properly and working.....

                  addLinkItem(KDW, linkLabel, urlPath)


                  scratching my head on this ?????
                  • 6. Dynamic Accordion 2-Levels deep
                    Garyl Woolworth Level 1
                    Could you test one thing real quick and tell me what the results are before this line addLinkItem(this['TB'+ iPanel + "-" + iTab], linkLabel, urlPath) can you do mx.controls.Alert.show(this['TB'+ iPanel + "-" + iTab].height.toString()); This will tell us if the component is ready to have children added to it as well as if the reference to the component is correct. If you do not get a number as in undefined or it throws an error then you know it's a problem with the VBox itself which could be that you are trying to add link buttons to the VBox before it's ready to accept them or the path to that VBox is incorrect. Let me know.
                    • 7. Re: Dynamic Accordion 2-Levels deep
                      Kevin D. Wright Level 1
                      I added the line " Alert.show(this['TB'+ iPanel + "-" + iTab].height.toString()); "
                      but I get no alert at all and no error?? nothing happens??
                      • 8. Re: Dynamic Accordion 2-Levels deep
                        Kevin D. Wright Level 1
                        I was able to achieve this using a different method;

                        1. Returning XML instead of a query object from my remote object.
                        2. Loop through the XML nodes using nested repeaters hard coded in the mxml.

                        code follows;

                        <mx:Panel width="100%" height="33%" layout="vertical" id="panel1" title="">
                        <mx:Accordion id="Ac1" width="100%" height="100%" >
                        <mx:Repeater id="repeatAc1" dataProvider="{MenuXML.tab}" >
                        <mx:VBox width="100%" height="100%" label="{repeatAc1.currentItem.label}" >
                        <mx:Repeater id="repeatlinkAc1" dataProvider="{repeatAc1.currentItem.link}" >
                        <mx:LinkButton label="{repeatlinkAc1.currentItem.label}" data="{repeatlinkAc1.currentItem.url}" click="followLink(event)" />
                        </mx:Repeater>
                        </mx:VBox>
                        </mx:Repeater>
                        </mx:Accordion>
                        </mx:Panel>

                        this is a sample of the XML data I'm returning from the remote object;
                        <panel>
                        <panelID>3</panelID>

                        <tab>
                        <label>Fund - Portfolio Profile</label>
                        <link>
                        <label>Investor Information</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        <link>
                        <label>Subscription Lender Information</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        </tab>

                        <tab>
                        <label>Legal Documents</label>
                        <link>
                        <label>Subscription Agreements</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        <link>
                        <label>Private Placement Memorandum</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        <link>
                        <label>Limited Partnership Agreement</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        <link>
                        <label>Amendments to LPA</label>
                        <url>index.cfm?DocID=</url>
                        </link>
                        </tab>

                        </panel>



                        Thanks Kaotic101 for your help earlier!
                        Kevin (Kdub)