Tree View using Visualforce with no plugins

Visualforce Apr 9, 2015

Use Case

To Show Records in Hierarchy/Tree view using Visualforce

Components Used

  1. Visualforce Page
  2. Apex Controller
  3. jQuery
  4. Bootstrap

Visualforce Page, Apex Controller works fine if you copy & Paste as given

Visualforce Logic

So Logic behind displaying hierarchy view was achieved simply using <ul> & <li> elements

So if you want a view of Account => Contacts =>Cases,

<ul>
    <li> // first li
        <!-- place your content here for first node/level -->
        <ul>
            <li> // second li
                <!-- place your content here for Second node/level -->
                <ul>
                    <li> // third li
                        <!-- place your content here for Second node/level -->
                        <!-- So on repeat <ul> & <li> to dig into more level-->
                    </li> // end of third li
                </ul>
            </li> // end second li
        </ul>
    </li> // end first li
</ul> 

NOTE: you can use this with repeat/dataTable tags eithers, example explainded below

Visualforce Page (Actual)

<apex:page controller="GetAccountContacts" showHeader="false" sidebar="false">
    <!-- Mobile View -->
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <!-- jQuery CDN Reference -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <!-- Bootstarp css & Combined Css -->
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet" />
    <style>
        .tree {
            min-height: 20px;
            padding: 19px;
            margin-bottom: 20px;
            background-color: #fbfbfb;
            border: 1px solid #999;
            -webkit-border-radius: 4px;
            -moz-border-radius: 4px;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
            -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05)
        }
        
        .tree li {
            list-style-type: none;
            margin: 0;
            padding: 10px 5px 0 5px;
            position: relative;
        }
        
        .tree li::before,
        .tree li::after {
            content: '';
            left: -20px;
            position: absolute;
            right: auto;
        }
        
        .tree li::before {
            border-left: 1px solid #999;
            bottom: 50px;
            height: 100%;
            top: 0;
            width: 1px;
        }
        
        .tree li::after {
            border-top: 1px solid #999;
            height: 20px;
            top: 25px;
            width: 25px;
        }
        
        .tree li span {
            -moz-border-radius: 5px;
            -webkit-border-radius: 5px;
            border: 1px solid #999;
            border-radius: 5px;
            display: inline-block;
            padding: 3px 8px;
            text-decoration: none;
        }
        
        .tree li.parent_li>span {
            cursor: pointer !important;
        }
        
        .tree>ul>li::before,
        .tree>ul>li::after {
            border: 0;
        }
        
        .tree li:last-child::before {
            height: 30px;
        }
        
        .tree li.parent_li>span:hover,
        .tree li.parent_li>span:hover+ul li span {
            background: #eee;
            border: 1px solid #94a0b4;
            color: #000;
        }
    </style>
    <div class="tree well">
        <apex:repeat value="{!AccConCases}" var="a">
            <ul>
                <li>
                    <span><i class="icon-folder-open icon-plus-sign"></i>Account</span> <a href="/{a.Id}"  target="_blank">{!a.Name}</a>
                    <ul>
                        <apex:repeat value="{!a.Contacts}" var="c">
                            <li>
                                <span><i class="glyphicon glyphicon-user"></i> Contact</span><a href="/{!c.Id}"  target="_blank"></a> {!c.Name}
                                <ul>
                                    <apex:repeat value="{!a.Cases}" var="ca">
                                        <li>
                                            <span><i class="glyphicon glyphicon-briefcase"></i> Case</span><a href="/{!ca.Id}" target="_blank"></a> {!ca.CaseNumber}
                                        </li>
                                    </apex:repeat>
                                </ul>
                            </li>
                        </apex:repeat>
                    </ul>
                </li>
            </ul>
        </apex:repeat>
    </div>
    <script>
    $(function() {
        $('.tree li:has(ul)').addClass('parent_li').find(' > span').attr('title', 'Collapse this branch');
        $('.tree li:has(ul)').addClass('parent_li').find(' > ul > li').hide('slow');
        $('.tree li.parent_li > span').on('click', function(e) {
            //alert('clicked');
            var children = $(this).parent('li.parent_li').find(' > ul > li');
            if (children.is(":visible")) {
                children.hide('fast');
                $(this).attr('title', 'Expand this branch').find(' > i').addClass('icon-plus-sign').removeClass('icon-minus-sign');
            } else {
                children.show('fast');
                $(this).attr('title', 'Collapse this branch').find(' > i').addClass('icon-minus-sign').removeClass('icon-plus-sign');
            }
            e.stopPropagation();
        });
    });
    </script>
</apex:page>

Controller

public class GetAccountContacts {        
    public List<Account> getAccConCases(){
        return [select id, Name, (select id, Name from Account.Contacts), (select id, ContactId, CaseNumber from Cases) from account LIMIT 10];
    }                
}

Sample Output

Youtube Demo Link

Phanindra Mangipudi

Salesforce, Lightning Web Componets, Node.Js, Angular 2+, Bootstrap