codescience-resource-reatured-image-generic

In our last thrilling episode, we introduced the Handlebars Javascript templating library, and demonstrated two very simple-use cases for rendering templates in a Visualforce page backed by Javascript Remoting. Today, we’ll increase the complexity a bit by using Handlebars’ partial templates to render a nested data structure generated through recursion in Apex. We’ll build on some of the code we used in Part 1. So if you haven’t read that, go ahead and check it out first. We’ll make an all-new page for this example, but will leverage the Controller, Component, and CSS we created last time because we strive to be lazy, as any self-respecting programmer should.

In the screenshot above, you can see that we’ve gone six levels deep in our hierarchy of bears. From Papa to Sister Bear to GrandBaby Bear to Bobo to Bobo JR to Bobo III. You’ll also see that GrandBaby Bear‘s son Tito has ten mouths of his own to feed. Thankfully, we only have to render them, not feed them. Let’s start with another bare bones Visualforce page. It brings together our controller, stylesheets and javascript resources which are all maintained as separate assets in our Force.com instance.

<apex:page showHeader="true" sidebar="false" doctype="HTML-5.0" title="handlebears" controller="HandlebearsController">
    <head>
        <apex:stylesheet value="{!URLFOR($Resource.BearsCSS)}"/>
    </head>
    <div id="bearTree"/>
        <c:BearTemplates/>
            <!-- external js libraries loaded at the bottom of page -->
            <script src="https://code.jquery.com/jquery-2.1.0.min.js"/>
            <script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0-alpha.2/handlebars.min.js"/>
            <script src="{!URLFOR($Resource.HandlebearsTreeJS)}"/>
</apex:page>

Now we add two methods to our existing Handlebears.cls file. One is our JSR method, which will deliver our data, and the other is a recursive method we will call to build up a set of nested wrapper objects that mirrors the list of lists we want to build, and will work with any number of nested levels up to the maximum of 10MB we can return from a JSRemoting method. That’s a lot of bears!

//JSR method to return a nested tree of bears
@RemoteAction
global static Bear familyTree() {
    //use a Map to keep track of parentIds and a list of their children
    Map <String, Bear[]> BearIdToChildren = new Map <String, Bear[] >{};
    Bear__c rootBear;
    For (Bear__c bear : [Select Name,Id,Parent__c, Parent__r.Name, Adjectives__c, CreatedDate
    from Bear__c
    order by Name
    limit 5000]){
        //ony Papa Bear has no parent :(
        if(bear.Parent__c == null){
            rootBear = bear;
        }
        //build out the map
        if(BearIdToChildren.containsKey(bear.Parent__c)){
            //if the map contains the parent key, wrap this child and add it to the proper list:
            BearIdToChildren.get(bear.Parent__c).add(new Bear(bear));
        }else{
            //this bear's parent is not in our map. Create the list and add the wrapped child:
            BearIdToChildren.put(bear.Parent__c, new Bear[]{new Bear(bear)});
        }
    }
    //wrap Papa in a new Bear wrapper
    Bear papa = new Bear(rootBear);
    //recursively add all children from our map
    papa = addCubs(papa, BearIdToChildren);
    //return the root bear
    return papa;
}
//recursive method to build a nested set of Bear lists
private static Bear addCubs(Bear parent, Map <String, Bear[]> BearIdToChildren){
    //get the list of children
    parent.children = BearIdToChildren.get(parent.Id);
    for(Bear b: parent.children){
        if(BearIdToChildren.containsKey(b.id) ){
            //recursively call this method again
            addCubs(b,BearIdToChildren);
        }
    }
    return parent;
}
//a wrapper class for the bears makes for cleaner templates
global class Bear {
    public String name {get;set;}
    public String birthday {get;set;}
    public String id {get;set;}
    //a self-referring list to hold our cubs
    public Bear[] children {get;set;}
    public bear(){}
    public bear(Bear__c bear){
        this.name = bear.name;
        this.birthday = bear.CreatedDate.format('MM/dd/yyy');
        this.id = bear.id;
    }
}

Next, we will add some templates to the templates component we defined last time. We need one partial template for rendering a single bear and its children and another top-level template which invokes the partial template. For more about partial templates, check out the Handlebars.js github docs. In short, the partial template is provided context from each child object returned by our JSR method. Everything clicks neatly into place and we render an arbitrarily deep list (of lists (of lists (of lists))) of nested Bears.

<!-- template for root of the bear tree -->
<script id="tree-main-template" type="text/x-handlebars-template">
    <h1>{{name}}</h1>
    {{#each children}} {{> child}} {{/each}}
</script>
<!-- partial template for each branch of the tree -->
<script id="tree-child-template" type="text/x-handlebars-template">
    <ul class="bearTree">
        <li>
        <span><a href="/{{id}}">{{name}}</a></span>
        {{#each children}} {{> child}} {{/each}}
        </li>
    </ul>
</script>

You will notice that the way we invoke our JSR methods is a bit different than in Part 1. This time we show the alternate syntax for calling JSR that is especially useful when building code meant to be packaged in the Salesforce AppExchange. To package an app, you need to define a namespace for your packaged code to run in. But during development, you may have to run the code in an environment where that namespace has not been defined. The following syntax allows your JSR methods to run regardless of namespace, which can make development much less frustrating.

$(document).ready(function(){
    //register our partial template
    Handlebars.registerPartial("child", $("#tree-child-template").html());
    //compile our main template
    var treeTemplate = Handlebars.compile($("#tree-main-template").html());
    //Call JSR in a way that respects optional package Namespace
    Visualforce.remoting.Manager.invokeAction(
        //name of the class and method (without Namespace)
        'HandlebearsController.familyTree',
        //if there were arguments to our JSR method, they would be here.
        function(result,event){ //callback function
        if(event.status){
            //use the JSR results as context for a template
            console.log('tree:', result);
            $('#bearTree').html(treeTemplate(result));
        }else{
            alert('Could not fetch tree.');
            console.log(event.message);
        }
    },
    {escape: true} // extra JSR parameters
    );
});

Take a look at the Chrome dev console where we log our JSR results on line 22 of the Javascript above. I expanded a few of the child lists in order to show how you can easily inspect JSR data using modern JS dev tools.

Finally, let’s clean up our lists a bit to make sure them display consistently.

ul.bearTree {
font-family: sans-serif;
font-size: 18px;
list-style-type: disc;
margin:2px;
padding:0px;}

Now we can generate recursive data structures and render them via Javascript remoting methods and partial templates via Handlebars. This is also a useful technique for integrating with other libraries that expect a tree structure like the excellent JSTree, which is a great interface that needs a collapsible folder structure.