So I'm trying to implement a Tree Structure using FancyTree. I've gotten the tree to display, but I want to implement lazy loading, but I'm having some trouble.
Page:
<apex:component controller="TreeNodeViewController">
...
<apex:inputHidden id="nodeIdField" value="{!nodeId}" />
<apex:outputText id="test" value="{!loadedNode}" />
<apex:actionFunction name="getChildren" action="{!getNodeJSON}" oncomplete="console.log('first')">
<apex:param name="nodeId" value="" />
</apex:actionFunction>
<!-- Add code to initialize the tree when the document is loaded: -->
<script type="text/javascript">
$(function(){
// Attach the fancytree widget to an existing <div id="tree"> element
// and pass the tree options as an argument to the dynatree() function:
$("#tree").fancytree({
checkbox: {!selectable},
generateIds: false,
selectMode: 3,
source: {!JsonString},
select: function(event, data) {
...
},
lazyLoad: function(event, data){
var nId = data.node.key;
jQuery(document.getElementById("{!$Component.nodeIdField}")).val(nId);
getChildren(document.getElementById("{!$Component.nodeIdField}").value);
children = '{!loadedNode}';
console.log('second');
var arr = JSON.parse(children);
data.result = arr;
},
});
});
</script>
<!-- Add a <div> element where the tree should appear: -->
<div id="tree"> </div>
</apex:component>
Controller:
public class TreeNodeViewController {
public Boolean selectable {get; set;}
public String selectNodeKeys {get; set;}
public String loadedNode {get; set;}
{
selectable = false;
selectNodeKeys = 'No value selected';
loadedNode = '';
}
public String jsonData {get; set;}
public String getJsonString()
{
if (jsonData == null){
jsonData = NodeDisplay.getTreeJSON();
}
return jsonData;
}
public String nodeId {get; set;}
public void getNodeJSON()
{
String nId = ''+ApexPages.currentPage().getParameters().get('nodeId');
String value = NodeDisplay.getNodeJSON(nId);
loadedNode = value;
System.debug(value);
// return value;
}
}
NodeDisplay class:
public class NodeDisplay
{
private static Map <Id, Node__c> allNodes {get; set;}
private static List<Node__c> rootNodes {get; set;}
private static Map <Id, List<Node__c>> idToSubNodes {get; set;}
// Global JSON generator
private static JSONGenerator gen {get; set;}
static
{
init();
}
private static void init()
{
...
}
public static String getTreeJSON() {
gen = JSON.createGenerator(true);
gen.writeStartArray();
for(Node__c n : rootNodes)
{
NodeNode node = createNode(n.Id);
convertNodeToJSON(node);
}
gen.writeEndArray();
return gen.getAsString();
}
public static String getNodeJSON(String objId)
{
Id i;
try
{
i = Id.valueOf(objId);
}
catch(StringException e)
{
return '[]';
}
List<Node__c> subList = idToSubNodes.get(i);
gen = JSON.createGenerator(true);
for(Node__c n : subList)
{
NodeNode node = createNode(n.Id);
convertNodeToJSON(node);
}
return gen.getAsString();
}
private static NodeNode createNode(Id objId) {
NodeNode n = new NodeNode();
...
return n;
}
private static void convertNodeToJSON(NodeNode node)
{
gen.writeStartObject();
gen.writeStringField('title', node.name);
gen.writeStringField('key', node.id);
gen.writeBooleanField('unselectable', false);
gen.writeBooleanField('expanded', false);
gen.writeBooleanField('folder', true);
if (node.hasChildren)
{
gen.writeNullField('children');
gen.writeBooleanField('lazy', true);
}
gen.writeEndObject();
}
public class NodeNode {
...
}
}
I know it's a lot of code, and I tried to take out the less important sections. The loadedNode
field debugs correctly, but it doesn't get passed to the lazyload function correctly. After using some print statements, I found out that it looks like the lazyload tries to get the value of the loadedNode
field before the getChildren
function finishes ('second' prints before 'first'). This looks like just something that has to do with the way FancyTree does it's lazy loading, so I'm not sure if there is a way around this.
Any help is appreciated!