Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

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!

share|improve this question
    
Take a closer look at how to set Lazy Loading, after which you might want to look at the link to the Tutorial Load Data that's directly underneath it. –  crmprogdev Jun 30 at 23:36

1 Answer 1

I know this is old, but here's how I'm doing it.

$(function () {
    // Create the tree inside the <div id="tree"> element.
    $("#tree").fancytree({
        source: { url: "/Home/GetData", cache: true }
        , checkbox: true
        , icons: false
        , cache: true
        , lazyLoad: function (event, data) {
            var node = data.node;
            data.result = {
                url: "/Home/GetTreeViewData/" + node.key
                , data: { mode: "children", parent: node.key }
                , cache: true
            };
        }
        , selectMode: 3
        , select: function (event, data) { 
        }
        , strings: {
            loading: "Grabbing places and events…",
            loadError: "Load error!"
        },
    })
});

Basically, if you were to browse to mysite/Home/GetData, it returns a json result that looks like this

[{"key":1,"title":"Accommodations","lazy":true,"parentId":null},{"key":5,"title":"Attractions","lazy":false,"parentId":null},{"key":6,"title":"Dining","lazy":false,"parentId":null},{"key":7,"title":"Entertainment","lazy":false,"parentId":null},{"key":18,"title":"1","lazy":true,"parentId":null},{"key":23,"title":"2","lazy":true,"parentId":null}]

Now say you expand the first node, it's ID in the database is 1, and any children underneath it have a column called parentId with a value of one. When you browse to mysite/Home/GetTreeViewData/1 you get this

[{"key":2,"title":"Hotels","lazy":false,"parentId":1},{"key":3,"title":"Bed \u0026 Breakfast","lazy":false,"parentId":1}]

So I just pull the node.key as my Id and use it to load the children. Hope it helps.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.