Our Blog

As part of these series “How to populate a cf[…] with Remoting”, I wanted to show how to bring data into a cftree. This is the easiest way, but it has some limitations: your xml data has to have a label attribute and the tree is first closed when it loads. If you want to get around those, you will have to do more work with the data returned from the server (I may do it if I have time :)).

The function that handles the response it’s the same as in the cfgrid example:

responseHandler.onResult = function( results: Object ):Void {
   //when results are back, populate the cftree
   categories.dataProvider = results;
}

The main difference is in the cfc function. In this case, it will return an xml object. Each node has a label attribute and any other attribute we want. Important: You must remove all whitespace from the xml string.

<cffunction name="getCategories" access="remote" output="false" hint="Gets a tree in xml form">
   <cfset var categories = ""/>
   <!--- possibly make a query to get categories--->
   
   <!--- make the xml --->
   <!--- it looks awful, but all whitespace must be removed --->
   <cfxml variable="categories"><categories label="Categories" id="root"><category id="coldfusion" label="ColdFusion">the rest of the nodes...</category></categories>
   </cfxml>
      
   <cfreturn categories />
</cffunction>

And the form:

<cfform name="myform" format="Flash">
   <cftree name="categories"><!--- an empty tree --->
   </cftree>
   <cfinput type="text" label="Selected Item:" name="display" bind="{categories.selectedNode.getProperty('id')} = {categories.selectedNode.getProperty('label')}">
   <cfinput type="button" name="getValues" value="Populate tree" onClick="#getData#">
</cfform>

Note that to access other attributes in the xml node, you must reference them as:

myTree.selectedNode.getProperty('myAtribute');

A live example
Download the source

Laura

Laura

53 Comments

  1. CarlosM()

    CarlosM()

    Hi,

    I just want to say that the last few post from this blog have really inspired me and updating my code to use these features have taught me a lot, Thanks.

    If you could help me on this I would appreciate it.:)

    I’ve created a complex tree structure with several queries and a cftree format=”object” in a CFC.
    When I pass the variable from the CFC to populate the updateable cftree in the CFM, I get the structure but no content in the tree. The tree shows “ [object Object],1 ,,, null “ instead of the data.

    Is there a way to fix this? Or do I have convert the object in the CFC to an xml string before I pass it and if so how??? *&lt;;) Did that all make sense?

    Thanx again
  2. Brian Rinaldi
    I am simply populating my cftree with query data, but I cannot seem to figure out how to access the value of the selected tree item (i.e. the id). This works fine for the bind value: {searchTree.selectedNode.getProperty('label')} but this doesn't {searchTree.selectedNode.getProperty('id')}. The second returns empty. My tree is created as such:
    <cftree name="searchTree">
    <cfloop query="qryTree">
    <cftreeitem value="#qryTree.id#" display="#qryTree.title#" parent="#qryTree.parent#" expand="false" />
    </cfloop>
    </cftree>
    I am going crazy trying to figure this out...any help you can offer would be greatly appreciated.
  3. Brian Rinaldi
    Nevermind...after searching all over I finally found the answer...for anyone readint this that doesn't know:
    categories.selectedNode.getProperty('data').value
  4. CarlosM()

    CarlosM()

    Laura,

    "This is the easiest way, but it has some limitations: your xml data has to have a label attribute and the tree is first closed when it loads. If you want to get around those, you will have to do more work with the data returned from the server (I may do it if I have time :))."

    Do you think you can post on how to work around these limitation? The label attribute is keeping me from remoting data in from a search.
  5. Stephen Moretti
    I'm trying to get this working as an onLoad function rather than from a button.

    My code (pretty much your code, except with a query building the XML) works great from a button, but when I call it from onLoad I see the tree populate and then clear out.

    Any insights would be greatfully received.
  6. Laura
    Stephen,
    the problem is that after your data has loaded, the regular data tree gets loaded and it overwrites yours (since the original tree was empty, you see an empty tree).
    I don't know what you need to do, but the simplest way to avoid that is by having only the code that sets up the icons in the onload, and get the tree items normally. In this way, the tree will load, and it will acquire the new icons you set. That is, skip the remoting call. The only thing you will not be able to do is to set up an icon to a specific node, since the tree is not yet populated when you call it from the onload function.
  7. Laura
    I don't know why I thought you wanted to set up the tree icons. Forgive me.

    The first paragraph is still true. But if you just want to load a tree, I would use it as normal. No need to make a remoting call onload really, since that is exactly what the cfform does by itself unless you need to do some manipulation, like adding icons.
  8. Stephen Moretti
    No problem Laura. Thanks for your help.

    You're right. I should be loading the data normally in the first instance. I think I was having a Sunday afternoon brain failure moment :)
  9. Stephen Moretti
    Ahhh... now I remember why....

    If you load a cftree using a query and cfformtreeitem, data in the tree is accessed using categories.selectedNode.getProperty('data').value

    If you load data into a cftree via an XML packet then you access the data using
    categories.selectedNode.getProperty('data') without .value on the end.

    I don't know whether this is a bug or purposeful, but its very annoying and means I have to check to see if I'm actually getting a value back from the tree if I load it up from two different sources.

    Hence the reason why I was trying to standardise the way I populate the tree to grabbing data from a remote connection and XML packet.

  10. Carl Sawyer

    Carl Sawyer

    Does anyone know a way to set the selected node in a cftree after the form is loaded? Note that the tree is being loaded from a query object.
  11. Hi Carl,
    Are you using remoting for that?
    If that is the case, once you set the data to the tree, you need to loop for the node that you want .
    Then, open all the parents of that specific node until you reach the root. Lastly, selected it. It is a lot of work, so we may make a small example of that.
  12. Carl Sawyer

    Carl Sawyer

    Nahual,
    Thanks for the reply. No we are not using remoting for this because it wasn't necessary (but maybe now it is). What I can't understand is why the following won't work:

    myTree.selectedNode = myTree.getNodeAt(i);

    where it would be index corresponding to the node we want selected. We can't seem to find what methods and properties (in actionscript) are available to us on the cftree.
  13. Laura
    Carl,
    You could do that from a click of a button for example (I think the node has to be opened to do it). But you can't do it right after onload. First, because there is no onload :) Second, even if you use the onload hack, the biggest problem is that when the form loads, the data has not yet arrived, so running the above code will do nothing, as the tree would be empty. There is no way to tell exactly when the data loads.
  14. Carl Sawyer

    Carl Sawyer

    Laura,
    I tried that from a button (so I knew the data was loaded) but couldn't get it to work). In fact, any reference to getNodeAt() prevents the page from compiling.
  15. Carl Sawyer

    Carl Sawyer

    Laura,
    My mistake (it was getting late here on the east coast). Even when we use the right method :) we don't get the expected results. For example:
    alert(tree1.getTreeNodeAt(0).getProperty('data').value);

    does return the proper value however:
    alert(tree1.getTreeNodeAt(10).getProperty('data').value);

    always returns nothing even through there are several hundred nodes in the tree. Any thoughts on why? Thanks.
  16. Carl Sawyer

    Carl Sawyer

    As a follow up, the problem was that there was only one node at the root level. Now the issue is how to refer to deeper levels. I'll need to read some more on XML in actionscript. Thanks for the help. BTW, your site has been extremely helpful.
  17. Anu
    Laura,

    First of all, I must thank you for doing a great job at helping the developer community with CF Flash Forms. I am trying to pass a query object to a Tree at run-time using Flash Remoting and using the categories.dataProvider = results; only shows object tags. Do you know a way to render a Tree using a query returned from a CFC? I can do work around to format query to an XML object but that is a big overhead.

    I would really appreciate your help with this. Thanks.
  18. Carl Sawyer

    Carl Sawyer

    We did finally find a solution to our problem of selecting a particular node. Instead of using getTreeNodeAt() we used getItemAt(), as in:
    myTree.selectedNode = myTree.getItemAt(i);

    As a side note, Nahuel and Laura, your site has been extremely helpful in our work with Flash Forms. Thanks for all your advice.
  19. Christopher

    Christopher

    Hi,

    I've just started using Flash Forms/ActionScript and have found the discussions on AS Fusion very helpful. I'm building an application, which uses CFTree control to display a hierarchical menu structure (up to about four levels) on a Flash Form.

    I want all the Tree nodes to be populated dynamically (except the very first level (parent) nodes, which I'm displaying initially on form load). I want to show the child menus when the user selects a node.

    I'm having two problems with this approach:

    (1) The first level (parent) nodes are shown as leaf nodes instead of as parent nodes since they had no children when they were first created, making it is difficult to programmatically change them to folders from my ActionScript when I've retrieved their children.

    (2) Each time a node is selected its children are systematically duplicated and displayed under it using the code below. I don't want the children to be duplicated under the same parent folder.

    // Find the menus under the selected menu item
    function getChildNodes(itemID, parentID){
       
    // Process the result we have received
    getChildNodes_Result.onResult
    = function( results: Object ):Void{

    MenuTree.TreeDataProvider = results;

    var index = MenuTree.selectedIndex;
    for(var i = 0; i < results.length; i++){
       if(index != 0){
        // Add the node at index + 1
        MenuTree.addItemAt(
    index + 1, results.items[i].LABEL);
        }
    }
    }
    }

    Any help will be gratefully appreciated.

    Thanks
    Chris
  20. CarlosM()

    CarlosM()

    help,

    I'm starting to use flex and no one on the flex side could answer.

    I created a CFC that has a flash cftree and I want to send that object to flex. When I set the returntype to any and the &lt;cftree format=&quot;object&quot; in my CFC, I get the correct hierarchy in flex but the data shows only “ [object Object],1 ,,, null “.

    There's got to be a way.
  21. Christopher

    Christopher

    Hi Carlos,

    My tree has up to five levels and I built in ColdFusion using a recursive custom tag to populate it when the page loads. Within my action script I use published Flex methods to add and remove tree items. This works fine except that I have the problem of not being able to refresh the tree after adding a node to the tree.

    I think I have seen the behaviour you are describing before. Perhaps, I can offer some advice if you provide some code fragment to shwo what you rae doing?

    Christopher
  22. CarlosM()

    CarlosM()

    Thanks Christopher I would really appreciate it.

    This is my CFC:

    <cffunction name="searchTree" output="false" access="remote" returntype="any">
    <cfargument name="forInput2" default="11A005" type="string" required="no">

    <!--Master Query end item with assemblies and components--->
    <cfquery name="rsBill" datasource="fshift">
    SELECT parent, component, insp_lt FROM bommaster WHERE (parentdist = '#arguments.forInput2#')
    </cfquery>

    <!---Parts with master as parent ---->
    <cfquery dbtype="query" name="run1">
    SELECT * FROM rsBill
    WHERE insp_lt = 1
    </cfquery>

    <!---components showing child items --->
    <cfquery dbtype="query" name="run2">
    SELECT * FROM rsBill
    WHERE insp_lt > 1
    </cfquery>

    <cfform name="form1" height="800" format="html">

    <cftree name="searchTree" format="object">

    <!---First run gives all parts and assemblies under masterItem --->
    <cftreeitem value="#arguments.forInput2#">
    <cfoutput query="run1">
    <cftreeitem value="#component#"
    parent="#arguments.forInput2#">
    </cfoutput>

    <!--- Second run loops db and places parts and components under their parent --->
    <cfoutput query="run2">
    <cftreeitem value="#component#"
    display="#component#"
    parent="#parent#">
    </cfoutput>
    </cftree>
    </cfform>
    <!-- return tree object --->
    <cfreturn #searchTree#>
    </cffunction>

    </cfcomponent>

    When I invoke this CFC I get the tree and all the data I need but with no label="part#". I get <node display="" value="" path="", but no label.
    Now in Flex, if I set the dataProvider to the searchTree object that is pasted from the CFC, I get the structure but no data. Is there a way to send the dataProvider that cfform creates for the cftree in my cfc in ActionScript so I don't loose anything? If there's anything more I can tell you that would help please let me know?

    Thanks again

  23. Christopher

    Christopher

    Hi Carlos,

    Sorry for the late reply.

    I'm not entirely sure why you're not seeing the label but the problem may be the way you are populating your tree. Perhaps, you could try populating the parent nodes first, followed by the parts and components. Also, you may consider using cfloop instead of cfoutput because I've used cfoutput before with some limitations. Below is an example code I used before changing to using a recursive tag. This worked except that it wasn't as dynamic as I wanted.

    Also, I found that using TreeDataProvider(an interface to hierarchical tree data and menu controls) is better than using dataProvider for a CFTree control.

    Please note the placement of the loops (loops within a loop!):

    <cfformgroup type="page">
    <!--- An empty tree --->
    <cftree name="MenuTree" format="flash">
                
    <!--- Specify the root level for the tree as Menu --->
    <cftreeItem value="Menu" expand="yes" img="fixed">

    <!--- Loop over the parents query and display each top level menu --->

    <cfloop query="GetParents">
    <cftreeitem value="#GetParents.label#" parent="Menu" expand="no" img="folder">
                   
    <!--- Get the branches for each parent --->
    <cfquery name="FirstLevelBranches" datasource="dev_flp">

    SELECT * FROM crm_menu
    WHERE PARENT = #GetParents.ID#
    </cfquery>
                   
    <!--- Cycle through the branches and display them under their parent --->
    <cfloop from="1" to="#FirstLevelBranches.recordcount#" index="i">

    <cfif FirstLevelBranches.recordcount GT 0 >
    <!--- It's a parent node --->
    <cftreeitem value="#FirstLevelBranches.label[i]#" parent="#GetParents.label#" expand="no" img="folder">
    <cfelse> <!--- It's a leaf node --->
    <cftreeitem value="#FirstLevelBranches.label[i]#" parent="#GetParents.label#" expand="no" img="document">
    </cfif>
    </cfloop>
                   
    <!--- Get children of the first branches --->
    <cfquery name="SecondLevelBranches" datasource="dev_flp">
    SELECT * FROM crm_menu
    WHERE PARENT = #FirstLevelBranches.ID#
    </cfquery>

    <cfloop from="1" to="#SecondLevelBranches.recordcount#" index="x">
    <cfif SecondLevelBranches.recordcount GT 0>
    <cftreeitem value="#SecondLevelBranches.label[x]#" parent="#FirstLevelBranches.label#" expand="no" img="folder">
    <cfelse>
    <cftreeitem value="#SecondLevelBranches.label[x]#" parent="#FirstLevelBranches.label#" expand="no" img="document">
    </cfif>
    </cfloop>
    </cfloop>
    </cftree>
    </cfformgroup>
  24. CarlosM()

    CarlosM()

    I'll give cfloop a shot. Thanks.

    So how do I pass the tree object in my CFC to populate a tree in flex or a tree in a cfm page?

    This is killing me!!!
  25. Chris
    Carlos,

    I'm not sure how you would pass the tree object in your CFC to populate the tree in flex.

    In my previous reply I showed the code I wrote as a first stab for my project. I realised the approach wasn't quite dynamic so I used recursion to build a fully populated tree on form load.

    Here is the code:

    // From the Form, call the recursive coldFusion tag:

    <!--- Insert the root level static tree item --->
    <cftreeitem value="0" parent="0" expand="yes" display="Menu" img="Computer">
                
    <!--- Generate the rest of the tree --->

    // This is how to call the custom tag
    <cf_recurse>

    // This is the contents of the custom tag i.e. recurse.cfm

    <cfquery name="GetParents" datasource="dev_flp">
    SELECT *
    FROM CRM_MENU
    WHERE parent = #attributes.parentItemID#
    </cfquery>

    <!--- Loop through the GetParents query and create a tree for each parent --->
    <cfloop query="GetParents">
    <cfif GetParents.recordcount GT 0>
    <!--- This must be a parent node --->
    <cfset image = "Folder">
    <cfelse>
    <!--- This must be a leaf node --->
    <cfset image = "Document">
    </cfif>
       
    <!--- Create the tree item --->
    <cftreeitem value="#ID#" parent="#attributes.parentItemID#" display="#label#" img="#image#" expand="no">
       
    <!--- Find children of the current parent --->
    <cfquery name="GetChildren" datasource="dev_flp">
       SELECT *
       FROM CRM_MENU
       WHERE parent = #GetParents.ID#
    </cfquery>
       
    <!--- If there is a child for the parent, call recurse again but this time make the parentItemID equal to the ID of the current child item. --->

    <cfif GetChildren.recordcount GT 0>
    // recursive loop
    <cf_recurse
    parentItemID = "#GetParents.ID#">
    </cfif>
    </cfloop>

    To add a tree item I do:

    responseHandler.save_Result = function( results: Object ):Void {

    // Selected item will be the parent of the new item
    var index = MenuTree.selectedIndex;

    for(var i = 0; i < results.length; i++){
    // check user has not selected the static tree item
    if(index != 0){
    MenuTree.addItemAt(index + 1, label);

    // where label is the display value from the result object.
    }
    }
    }

    Similarly to update a menu item I do within the save_Result:

    // This will replace the edited menu item
    MenuTree.replaceItemAt(index, label);

    Note: the only problems I have with this approach
    is that I cannot refresh my tree to show the correct database values except I reload the page -not nice!

    Hope this helps.
    Chris

  26. Chris
    Hi Carlos,

    I have recreated your original problem i.e.

    "When I set the returntype to any and the
    <cftree format="object" in my CFC, I get
    the correct hierarchy in flex but the data
    shows only “ [object Object],1 ,,, null “.

    As I stated in my second posting the reason
    you are seeing [object Object],1 ,,, null “
    is because you are doing something like

    SearchTree.dataProvider = results;

    This will definitely produce the behaviour you are seeing. I have tried in my code and produced the following:

    [object Object],1 ,,[object Object], null

    The proper thing to do I think is in responseHandler.onResult:

    SearchTree.TreeDataProvider = results;

    BTW: You said "I get the correct hierarchy in flex but the data shows only ..." Judging from what I've seen, it's probably not the hierarchy that you are seeing.

    Any more problems just shout!
    Chris
  27. CarlosM()

    CarlosM()

    I tried TreeDataProvider and it didn't work. There has got to be a way to do this! I'm not giving up until I know for a fact why you can't do it...:(

    Man, I wish I could go to MAX...

    Well Chris, Thanks for giving me your time and effort. I really appreciate it.

    Take it easy
  28. Bradford

    Bradford

    Is there a way to bind a Cftree to a CFSELECT?
  29. schwag
    Is anyone having a problem getting openDuration to work on the tree? All other styles appear to work fine, even selectionDuration.

    I tried doing it with a global style:

    _global.styles.Tree.setStyle(&quot;openDuration&quot;, 600);

    then also in line:

    style=&quot;open-duration:600;&quot;

    Neither seem to work? am I doing something wrong in code or is this a CF server bug?
  30. joel johnston
    Carlos, Did you ever figure this out? I'm in an identical spot on this one where I need to refresh the cftree with an entry recently submitted. Let me know.

    Thanks
  31. Jeremy

    Jeremy

    Does anyone have an example of populating with remoting by query? When I try I get the
    [object Object],1 ,,[object Object], null
    problems.
    BTW, this site is great, we're just starting to fool with this fancy stuff and most of the questions I have are on here!
  32. Laura
    Jeremy,
    It is a little difficult to do if you don't know ActionScript. The easiest way is to loop over the query and create the xml as it is shown in the post example.
    But to give you an idea, you would have to loop over the query in actionScript, adding each item to the root (or whatever node you want) by addTreeNode(&quot;My Label&quot;)

    for (var i = 0; i &lt; results.length; i++){
       var node = parentNode.addTreeNode(results.items[i].Name, results.items[i]);
    }

    The code above assumes you have a variable called parentNode pointing to the root or node where you want to add the children. It also assumes your query has a column called Name.
    It may not work as is for your case, it is just an idea of what you might do. ;)
    That is what I use in the file explorer application if you want to see how I did it by sending a query, particularly the getDirectories_Result function

    Hope that helps
  33. Jeremy
    Gotcha on the query stuff. Now....is it possible to dynamically set the href and target properties for nodes? I don't see those properties in the Flex documentation for tree, and trying:

    tree1.getTreeNodeAt(0).href = &quot;http://google.com&quot;;
    tree1.getTreeNodeAt(0).target = &quot;_blank&quot;;

    did nothing (didn't break code, but didn't work either)
    Also, once populated from Flash Remoting, I'd like the tree to open up at the root to show the level 1 leaves. Trying this didn't do anything:

    tree1.setIsOpen(0,true,true,true);

    Thoughts?
  34. Jeremy
    hmmm...typing this out allowed me the perspective to figure out the opening:

    tree1.setIsOpen(tree1.getTreeNodeAt(0),true,true,true);

    =)

    How about getting rid of the border?

    tree1.border = "no";

    doesn't work.
  35. Derek Bezuidenhout
    Don't forget to use xmlFormat around any data in your id or label if either might contain & or > or < or " type of characters.

    Thanks for the great site!
  36. Chris
    Jeremy ...

    if you want to get rid of the border, use the style attribute in the cftree tag:

    <cftree style="borderStyle:none;" />
  37. Tito Chatzis
    Does anyone have any idea how to preserve selected cftreeitem data and its expanded state after submitting the page? I have a Flash cfree in a regular cfform. It is imperative that my page is submitted, so what I am looking for is to bind my #form.selectedNodeID# to the Flash tree to highlight the correct node and expand it.
  38. casey
    Hi all.... Here's the situation, I'm populating a multi level tree then filtering that data into a grid...
    Here's what I've noticed:
    The tree is filtering correctly, the grid is maintaining data that should be removed by the tree selection. I think this is occuring because of the way or organization is structured...

    The Directors are also someone's immediate Manager.
    The Tree is giving the appropriate filtered view, whereas the grid is showing the view for the Director in the lower branch rather than filtering on the Manager level.

    Here's the code and hopefully a better explanation of the problem:

    <cfquery name="users" datasource="#application.dsn.oiws#">
    SELECT *, LAST_NAME + ',' + FIRST_NAME AS EENAME
    FROM tbl_employee_master
    WHERE VP = 'VP, Sally'
    ORDER BY EENAME
    </cfquery>

    <cfform name="myForm" format="flash" height="355" width="700" skin="haloSilver">
       <cfformitem type="script">
          function applyFilter( term:String, grid:mx.controls.DataGrid, columns:Array ):Void {
          
             var filterTerm:String = term.toString().toLowerCase();
          
             if(filterTerm.length > 0) {
                if(_global.unfilteredData[grid.id] == undefined){
                   if (_global.unfilteredData == undefined){
                      _global.unfilteredData = {};
                   }
                   _global.unfilteredData[grid.id] = grid.dataProvider.slice(0);
                }
                
                var filteredData:Array = [];
          
                for(var i = 0; i< _global.unfilteredData[grid.id].length; i++) {
                   var item:Object = _global.unfilteredData[grid.id][i];
                   var added:Boolean = false;
                   
                   for(var j = 0; j< columns.length; j++){
                       if(!added){
                         var value:String = item[columns[j]].toString().toLowerCase();
                         if(value.indexOf(filterTerm) != -1)   {
                            filteredData.push(item);
                            added = true;
                         }
                      }
                      else {
                         break;
                      }
                   }
                }
          
             grid.dataProvider = filteredData;
          
             }
             else {
                if(_global.unfilteredData[grid.id] != undefined) grid.dataProvider =

    _global.unfilteredData[grid.id];
             }
          }
       </cfformitem>




    <cfformgroup type="panel" label="Tree View" height="345">

          <cfformgroup type="VBox" Height="150">

    <cftree
    format="flash"
    Name="tree1"
    onchange="applyFilter(tree1.selectedNode.getProperty('data').value,data,['VP', 'DIRECTOR', 'MANAGER', 'EENAME'])"
    Width="250"
    HScroll="yes"
    VScroll="yes"
    Border="yes"
    AppendKey="yes">

    <cftreeitem value="VP, DIRECTOR, MANAGER, EENAME"
    display="VP, DIRECTOR, MANAGER, EENAME"
    query="users"
    queryasroot="no"
    expand="Yes,no,no">
    </cftree>

          </cfformgroup>

          <cfformgroup type="panel" height="145" label="View For /{tree1.selectedNode.getProperty('data').value}/">
             <cfgrid name="data" height="100" query="users" rowheaders="false">
                <cfgridcolumn width="100" name="EMPLID" header="Employee ID">
                <cfgridcolumn width="100" name="RACFID" header="RACF ID">
                <cfgridcolumn width="100" name="LAST_NAME" header="Last Name">
                <cfgridcolumn width="100" name="FIRST_NAME" header="First Name">
                <cfgridcolumn name="ROLE" header="Role">
             </cfgrid>
          </cfformgroup>
    </cfformgroup>
    </cfform>

    Example of bad data....

    User clicks on the tree at the Director Level:
    Tree and Grid display all employees that belong to that Director.

    User clicks on the same Director, only at the Manager level of the tree:
    Tree displays only employees that show this director as a manager.
    Grid maintains the Director level view, showing both employees that reference this person as a Director and a Leader.

    Hope that helps.... This is my first attempt at using a tree, so I've probably violated some obvious rule that's causing the grid to mess up.
  39. casey
    Just a quick update....
    The problem is here:
    onchange=
    "applyFilter(tree1.selectedNode.getProperty('data').value,emplList,['VP', 'DIRECTOR', 'MANAGER' 'EENAME' ])

    If there's a way for me to check where at in the node we are (node 1, 2, 3..) or even count how many \'s in the path exist... I could then say applyFilter....VP or VP, DIRECTOR, ETC....

    Any help on how to incorporate javascript into the onchange event of the cftree would be appreciated... Here's what I've been working on (but cftree doesn't wanna play):

    <script language="JavaScript">
    function countscript()
    {
    aString = tree1.selectedNode.getProperty('data').value
    temp = aString[:] # use slice to make a copy
    count = 0
    index = temp.find('\')
    while index != -1:
    count += 1
    temp = temp[index + 1:] # use slicing
    index = temp.find('\)
    alert("I found %d occurrences of '\' in %s" % (count, aString));
    }
    </script>
  40. Tito Chatzis
    <script language="JavaScript" type="text/javascript">
    function callAction(thisNodeID)
    {
    document.tree.selectedNodeID.value = thisNodeID;
    document.tree.submit();
    }
    </script>

    <cfsaveContent variable="onClick">
    var thisNodeID = nodes.selectedNode.getProperty('data').value;
    var command = "javascript:callAction(" + thisNodeID + ")" ;

    getURL(command);
    </cfsavecontent>

    <cftree name="nodes" format="flash" required="no" delimiter="," completePath="yes" appendKey="no" highlightHref="yes" lookAndFeel="windows" font="helvetica" fontSize="11"   italic="no" bold="no" height="400"   width="250" vSpace="0" hSpace="0" align="left" border= "no"   hScroll="yes" vScroll="yes" enabled="Yes" visible="Yes" tooltip="Select Page" notSupported="Get Flash" onChange="#onClick#" style="borderStyle:none;">
    <cftreeitem value="0" display="ROOT" parent="nodes" expand="yes">
    </cftree>
  41. casey
    hi tito, not sure if that response was for me or not...
    i did try and use some of that code, but the page refused to load for me...

    right now i'm trying to determine the node(0), (1), etc....
    ultimately i'm thinking something like this:
    replace getTreeNode with whatever will tell me if we're at 0, 1, 2...etc...

    if (tree1.getTreeNode(0))
    {
       applyFilter(tree1.selectedNode.getProperty('data').value,emplList, ['VP'])
    }
    else if (tree1.getTreeNodeAt(1))
    {
       applyFilter(tree1.selectedNode.getProperty('data').value,emplList, ['DIRECTOR'])
    }
    else if (tree1.getTreeNodeAt(2))
    {
       applyFilter(tree1.selectedNode.getProperty('data').value,emplList, ['MANAGER'])
    }
    else if (tree1.getTreeNodeAt(3))
    {
       applyFilter(tree1.selectedNode.getProperty('data').value,emplList, ['EENAME'])
    }
    else
    {
       applyFilter(tree1.selectedNode.getProperty('data').value,emplList, ['VP'])
    }

    Thanks again!

    Sorry for being a noob!

    Casey
  42. jeff
    I am remoting a tree and would like to get data from the tree once it is selected.

    In the past I have used the following code without remoting:

    tree.selectedNode.getProperty('data').value


    Now that I am remoting the tree from a query I can't use this anymore. I was thinking that maybe the proper way to modify this code is by doing the following:

    //When I made the node I gave it the following properties:
    for (loop.....)
    Data = results.getItemAt(i);

    tree.addTreeNode(Data.Title, Data.ActivityID);

    //on selection I run this code:


    tree.selectedNode.getProperty('ActivityID')


    I tried many combinations but I haven't been able to get the correct data. Does anybody know how to reference this?

    Thank you for your time!
    Jeff
  43. Jeff
    Figured it out:

    I did the following to find the data:
    Programs.getNodeDisplayedAt(Programs.selectedIndex).getProperty('data')
    Hopefully this might help somebody.
  44. shawn gibson
    I am trying to get a handle on how to populate a tree in an actual.fla with entries from a database (Access or mySQL, doesn't matter). I am using coldfusion.

    I don't get the sense this project here would be able to be re-jigged for that use, would it? It seems to actually only be relevent for CF pages, not Flash files per se...as with much of the CF code available for use with Flash. Am I correct?

    I'm not certain how the connectivity all works yet, trying to grasp remoting, xml, CF, flex and db concepts all at once.

    I can certainly use this type of page you have here, in CF, for admin purposes, but I'd be very happy if I could actually build this type of thing directly into my Flash projects...Any suggestions?

    Shawn
  45. Peter
    hello. i have similar to above problems with referencing tree data. i populate my tree with flash remoting, with xml format data that looks like:

    <rootNode display="something">Some text
    <parentNode display="something">Some text
    </parentNode>
    </rootNode>

    I know how to address this attribute data (here = "something"), but how to address this "Some text" data?

    Thanks in advance
  46. Prema
    Hi Laura,

    I am using CFMX 7. I have a CFTREE built from a query. Would you please help me with the following :

    1. How do I check, if the value of a node matches with the value passed thru URL?
    2. Tree.getTreeNodeAt(0).getProperty('data').value gives the value of the root. But how to get the value of the child nodes? Is there any function available?

    Thanks in advance.
    Prema
  47. Jeff
    Ok, perhaps a little more help on the remoting part of populating the tree with remoting. My form loads the tree for the first time using a query just fine. When the user changes values in a cfgrid, the handler assigns the tree.dataProvider to the xml variable, as in this article. The page loads fine, the tree populates and I can get the path value from the query data using binding to myTree.selectedNode.getProperty('data').path. But when the tree repopulates from the xml variable, I am unable to get any tree path, losing the binding, and can only get the individual node value using myTree.selectedNode.getProperty('label'). I need to get the path to the selectedNode in either situation - from query data, or from the XML data. Is there any way I can do that with the xml dataProvider? I searched through the liveDocs but couldn't find what I needed.
  48. Alain
    Hi,

    A late contribution to this site, which has with no doubt been the most helpful source of my whole professional life...

    It looks like the question of pre selecting a particular node once the tree has been loaded has remained open. I have written a piece of code to do so, which I would like to share here. Although I am aware this technology seems obsolete now everyone has moved to Flex & more, I still hope it could help somebody... or am I the only one still using CF8 and Flashforms?!

    The idea is the following: Once the data has loaded, the tree is fully opened, then looped from the bottom upwards and the nodes are closed or not, depending on whether they hold the leaf that needs to be preselected. The code to open all nodes has been borrowed from www.sustainablegis.com/blog/cfg11n/index.cfm?mode=entry&entry=FC680842-20ED-7DEE-2A2E14FBEFD0601A

    My XMl uses 2 special attributes: rank (anything you want...) and depth, which increases for each sub node. Here we go...

    public function getmynode(mynodename:String, mynodevalue:String):Void {

    //open everything

    var theTree=categories; //cftree name

    var i=0;
    var mydepth=0;

    var thisNode=theTree.getTreeNodeAt(i);
    while (thisNode != undefined){
    if (theTree.getIsBranch(thisNode) && ! theTree.getIsOpen(thisNode)){
    theTree.setIsOpen(thisNode,true);
    }
    i++;
    thisNode=theTree.getNodeDisplayedAt(i);

    }
    //loop from the bottom of the tree upwards)      
    for ( var j=i; j>-1; j-- ) {

    //find out if j level is a branch

    if (theTree.getIsBranch(theTree.getNodeDisplayedAt(j)) && theTree.getIsOpen(theTree.getNodeDisplayedAt(j))){
    //it is an open branch so close it
    theTree.setIsOpen(theTree.getNodeDisplayedAt(j),false);
    }
    //It is a leaf
    else {

    //check if rank is mynodename
    if(theTree.getNodeDisplayedAt(j).getProperty('rank')==mynodename){
    //ok. The rank is right. Now check the id
    if(theTree.getNodeDisplayedAt(j).getProperty('id')==mynodevalue){
    //ok we have found it. Now we need to exit the loop...
    mydepth=theTree.getNodeDisplayedAt(j).getProperty('depth');
    categories.selectedNode=categories.getItemAt(j);
    break;
    }
    }
    }
    }   
    //we need to go up and close the right branches
    for ( var k=j; k>-1; k-- ) {
    //check it is an open branch
    if (theTree.getIsBranch(theTree.getNodeDisplayedAt(k)) && theTree.getIsOpen(theTree.getNodeDisplayedAt(k))){
    //the first branch at a shallower level stays open
    if(theTree.getNodeDisplayedAt(k).getProperty('depth')< mydepth) {
    //branch stays open. just decreases the depth.
    mydepth --;

    }
    else {
    //close this branch
    theTree.setIsOpen(theTree.getNodeDisplayedAt(k),false);
    }
    }
    }   
    }

    That's it! It's neither pro nor clean code, cause I am not... but it works! However, it seems to be a bit slow on a tree with 10000 records, so any suggestion for improvement would be appreciated.

    Alain
  49. Scott
    Alain ,

    Can you share an example of your XML. The tree is closing Completely when I use your script.

    Thanks.
  50. Alain
    Hi Scott,

    I am away from the computer for a while, so won't be able to post more before a few weeks. This is a quick post from my Iphone, in Slovenia.

    I believe the problem you mention comes from your XML. The tree closes completely because it does not find a node to open that meets the criteria. Your XML categories should have the following attributes: depth, id and rank. Then, make sure that in the XML you return, there is a node which has the value mynodename for rank and mynodevalue for id.

    The code I am using is exactly what I have posted. The only thing I could post is the XML in the remote call, but won't be able to do that before at least a week.

    Let me know if you managed to make it work.

    Alain
  51. Alain
    Hi again,

    Am back... This is an example of the code I use to populate the tree. It loads a list of names (students), sorted first by initials, then last name and first name.

    <cfset var categories = ""/>

    <cfquery name="initialqry" datasource="mydatasource">
    SELECT DISTINCT upper(left(lastname,1)) as initial FROM students
    order by lastname asc
    </cfquery>

    <cfxml variable="categories"><categories label="Students List" id="Students" rank="" depth="0"><cfoutput query="initialqry"><category id="#initialqry.initial#" label="#initialqry.initial#" rank="initiale" depth="1"><cfquery name="nameqry" datasource="mydatasource">SELECT DISTINCT lastname FROM students where left(lastname,1) = "#initialqry.initial#" order by lastname asc</cfquery><cfloop query="nameqry"><category id="#nameqry.lastname#" label="#nameqry.lastname#" rank="lastname" depth="2"><cfquery name="firstnameqry" datasource="mydatasource">SELECT FirstName, StudentID FROM students where lastname = "#nameqry.lastname#" order by FirstName ASC</cfquery><cfloop query="firstnameqry"><category id="#firstnameqry.StudentID#" label="#firstnameqry.FirstName#" rank="StudentID" depth="3"></category></cfloop></category></cfloop></category></cfoutput></categories></cfxml>

    <cfreturn categories />


    I could then preselect the student whose StudentID is 100 by calling getmynode('StudentID', 100)

    I hope that helps. Alain