11 Replies Latest reply on Oct 5, 2007 11:37 AM by Arun_Vaish

    Database driven tree control

    steveh1234
      I am using CF with my Flex app and I would like to create a tree control that populates a heirarchy from a table that is setup like this:

      ---Table Subject---
      iSubjectId - Identity Primary Key (int)
      iParentSubjectId - ID of the Parent Subject or null for top level subjects (int)
      sSubject - Subject Name (varchar)

      I currently have a subject.as object, subject.cfc and subjectHandler.cfc (rename of subjectGateway.cfc created by the CF wizard)

      subject.as includes [RemoteClass(alias="extensions.components.subject")]

      and I am currently using this to connect and run readAllSubjects() to pull a straight list into a combobox
      <mx:RemoteObject
      id="roSubjectCfc"
      destination="ColdFusion"
      source="extensions.components.subjectHandler"
      showBusyCursor="true" result="subjectResultHandler(event)"/>

      Thanks in advance!

      Steve H.
        • 1. Re: Database driven tree control
          ntsiii Level 3
          Unless someone else knows some magic, you are just going to have to do this the hard way, using recursive database calls to build the xml tree. Of course, do it all on the cf side at once, then send the xml tree back to flex.

          Tracy
          • 2. Re: Database driven tree control
            ur_dtrain Level 1
            I do this with a RemoteObject call to my CFCs. I take the array of results and build an XML object by recursively calling a function to consume the array (each element has a similar parent ID as your structure). Here's an example of my code (I'm sure many others have done similar). I had originally hoped there was a pre-built function that you could inform which data field contained the id and parent id to do the whole thing automatically, oh well.

            private function buildCategoryNodes(currentParent:Object):XML{
            var currentNodes:XML = new XML(<node />);
            currentNodes.@label = catalogName;

            for(var index:Number=0; index<categories.length; index++){
            if(categories.getItemAt(index).parentid == currentParent){
            var thisNode:XML = new XML(<node />);
            thisNode.@label = categories.getItemAt(index).storecategoryname;
            thisNode.@data = categories.getItemAt(index).storecategoryid;
            var hasChildren:Boolean=false;
            var currentID:Number = categories.getItemAt(index).storecategoryid;
            for(var index2:Number=0; index2<categories.length; index2++){
            if(categories.getItemAt(index2).parentid == currentID){
            hasChildren=true;
            break;
            }
            }
            if(hasChildren){
            var subNodes:XML = buildCategoryNodes(currentID);
            thisNode.appendChild(subNodes.children());
            }
            currentNodes.appendChild(thisNode);
            }
            }
            trace(currentNodes.toXMLString());
            return currentNodes;
            }

            Hope this gets you started.
            • 3. Re: Database driven tree control
              steveh1234 Level 1
              Darin,

              That looks good and I may try that as well. I totally agree with you that the control NEEDS a built in way to do this. It is going to be such a common action.

              I was starting to get somewhere by making my object implement ITreeDataDescriptor like this

              public dynamic class subject implements ITreeDataDescriptor
              {

              public var iSubjectId:Number = 0;
              public var iQueueId:Number = 0;
              public var iParentSubjectId:Number = 0;
              public var sSubject:String = "";
              public var iCreatedById:Number = 0;
              public var dtCreated:Date = null;
              public var iDeletedById:Number = 0;
              public var dtDeleted:Date = null;
              public var children:subject[];
              ...

              All of my subjects appear in the tree in the appropriate hierarchy,
              but the problem is that all of the items show up as branches including
              the end points. I have tried implementing a custom public function
              isBranch(node:Object, model:Object=null):Boolean, and even making it
              always return false, but it never changed the problem.

              I can't seem to get it to work completely but I am so close.

              Any ideas?

              Steve

              • 4. Re: Database driven tree control
                ur_dtrain Level 1
                Yeah, I was getting the same thing. That's why I add a default 'node' at the top of the function that becomes the root node at the first level of recursion (and you can turn off display of it in a treee if you like). Then you'll notice that on subsequent calls I apply subNodes.children() to the returned data, essentially 'dropping' the nested root node that I don't want. Give it a try.
                • 5. Re: Database driven tree control
                  ur_dtrain Level 1
                  Steve,
                  I went ahead and posted my entire data package here:
                  DataManage package
                  • 6. Database driven tree control
                    mltv
                    Sorry to ask but how would I use the example you posted.
                    I have taken the code and put it in a file called "DataManager.as" and put it in a folder called "Classes".
                    How Do I call the function setData from my mail mxml file?
                    I tried
                    DataManager.DataManager.setData(categories);
                    Where "categories" is my array o results and got the errors:
                    1120: Access of undefined property DataManager.
                    and
                    1182: Package cannot be used as a value: DataManager.

                    As always I am sorry if this is a simple and basic question but I am taking it all in as fast as I can.



                    My Code:
                    <?xml version="1.0" encoding="utf-8"?>
                    <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute"
                    creationComplete="initComponent()"
                    xmlns="*"
                    xmlns:myClasses="Classes.*">

                    <mx:Script>
                    <![CDATA[
                    import DataManager.DataManager;
                    import mx.core.UIComponent;
                    import mx.collections.ArrayCollection;
                    import mx.utils.ObjectUtil;
                    import mx.controls.Alert;
                    import mx.rpc.events.FaultEvent;
                    import mx.rpc.events.ResultEvent;
                    private var _key:Object;
                    [Bindable]
                    public var categories:ArrayCollection = new ArrayCollection();
                    [Bindable]
                    public function get key():Object
                    {
                    return this._key;
                    }
                    public function set key(key:Object):void
                    {
                    this._key = key;
                    }
                    private function initComponent():void
                    {
                    refreshList(null);
                    }
                    public function refreshList(event:Event):void
                    {
                    this.dataManager.getMasterQuery(this.key);
                    this.dataManager.getGear(this.key);
                    }
                    private function server_fault(event:FaultEvent):void
                    {
                    // dump error message
                    Alert.show( ObjectUtil.toString(event.fault) );
                    }




                    private function getMasterQuery_result(event:ResultEvent):void
                    {
                    categories=event.result as ArrayCollection;;
                    DataManager.DataManager.setData(categories)
                    }
                    private function getGear_result(event:ResultEvent):void
                    {

                    }

                    ]]>
                    </mx:Script>

                    <mx:RemoteObject
                    id="dataManager"
                    showBusyCursor="true"
                    destination="ColdFusion" source="CF2.Source.cats">
                    <mx:method name="getMasterQuery" result="getMasterQuery_result(event)" fault="server_fault(event)" />
                    <mx:method name="getGear" result="getGear_result(event)" fault="server_fault(event)" />
                    </mx:RemoteObject>
                    </mx:Application>
                    • 7. Re: Database driven tree control
                      steveh1234 Level 1
                      I use it like this:

                      public var dm:DataManager = new DataManager();
                      dm.setData(s); // where s is my ArrayCollection of items
                      myTree.dataProvider = dm.getNodeAt(0);
                      • 8. Database driven tree control
                        mltv Level 1
                        Thank you.
                        After changing some code in the function setData so it matched the names I used in my database I got it to run.
                        It does not display a tree(as I am used to seeing one) but shows the raw XML code in the tree space.
                        Any Ideas while I try to figure it out?
                        • 9. Re: Database driven tree control
                          steveh1234 Level 1
                          Make sure in your tree tag that you have both

                          labelField="@label"
                          showRoot="false"

                          Let me know if that doesn't help and I will post all my code for you.
                          • 10. Re: Database driven tree control
                            mltv Level 1
                            That did it!
                            The tree looks great.
                            Now off to play with drag and drop and click events
                            Thank you.
                            • 11. Re: Database driven tree control
                              Arun_Vaish
                              I want to show the tree label name as a title of an alert box and node label name as a message in an alert box.So wat I suppose to do?Plz reply as soon as possible
                              Thanks
                              Arun Vaish