Aug 30, 2016

Dynamic nth Level Hierarchy in Salesforce

This blog is somewhat related to my previous post but with bit easy implementation and more generic. We have encountered this implementation multiple time so thought of sharing it with all.

Ever thought of replicating this feature in any of your custom object?


Now the only complication is, in case of self lookup you don't know the end node and where your loop should stop (to think about the logic). So hope I will make it easy for you.

*Note : My blog code formatter is not working properly, so please check the spaces before using the code.

Step 1 : Create an apex class called HierarchyController, as shown below and save it.

public with sharing class DynamicHierarchyForBlogController 
{
 public String objectApiName {get;set;}
 public String fieldApiName {get;set;}
 public String nameField {get;set;}
 public String currentsObjectId {get;set;}
 public String topParentId {get;set;}
 public String jsonMapsObjectString {get;set;}
 private String jsonString;
 private Map> sObjectIdMap ;
 private Map selectedsObjectMap ;
 private Map allsObjectMap;

 public DynamicHierarchyForBlogController() 
 {
  currentsObjectId = Apexpages.currentPage().getParameters().get('id');
     sObjectIdMap = new Map>();
  selectedsObjectMap = new Map();
  allsObjectMap = new Map();
 }
 
 public String getjsonMapString()
 {
  retrieveInfo();
  return jsonString;
 }
 
 public void retrieveInfo()
 {
  String dynamicQuery = 'SELECT ID ,' + fieldApiName + ' , ' + nameField + ' FROM ' + objectApiName + ' ORDER BY ' + fieldApiName + '  LIMIT 50000';
  for(sObject obj: Database.query(dynamicQuery))
  {
   allsObjectMap.put(obj.id,obj);
  }

  if(currentsObjectId != null)
  {
   String dQuery = 'SELECT ID FROM ' + objectApiName + ' WHERE id =\'' + currentsObjectId +'\'';
   List objList = Database.query(dQuery);
   currentsObjectId = objList[0].Id;
   retrieveTopParent(currentsObjectId);
   retrieveAllChildRecords(new Set{topParentId});
   for(String str : sObjectIdMap.keySet())
   {
    selectedsObjectMap.put(str,allsObjectMap.get(str));
   }
   jsonString = JSON.serialize(sObjectIdMap);
   jsonMapsObjectString = JSON.serialize(selectedsObjectMap);
  }
 }

 public void retrieveTopParent(String sObjectId)
 {
  if(allsObjectMap.keySet().contains(sObjectId) && allsObjectMap.get(sObjectId).get(fieldApiName) != null)
  {
   topParentId = String.valueOf(allsObjectMap.get(sObjectId).get(fieldApiName));
   retrieveTopParent(topParentId);
  }
 }

 public void retrieveAllChildRecords(Set sObjectIdSet)
 {
  if(sObjectIdSet.size() > 0)
  { 
   Set allChildsIdSet = new Set();
   for(String str : sObjectIdSet)
   {
    Set childsObjectIdSet = new Set();
    for(sObject obj : allsObjectMap.values())
    {
     if(obj.get(fieldApiName) != null && String.valueOf(obj.get(fieldApiName)) == str)
     {
      childsObjectIdSet.add(obj.Id);
      allChildsIdSet.add(obj.Id);
     }
    }
    sObjectIdMap.put(str,childsObjectIdSet);
   }
   retrieveAllChildRecords(allChildsIdSet);
  }
 }
}

Step 2 : Now create a component called Hierarchy, as shown below and save it.

<apex:component controller="DynamicHierarchyForBlogController">
 
 <apex:attribute name="objectName" description="Name of Object." type="String" required="true" assignTo="{!objectApiName}"/>
 <apex:attribute name="FieldName" description="Name of the field of the object." type="String" required="true" assignTo="{!fieldApiName}"/>
 <apex:attribute name="RepersenterField" description="Name field of the object." type="String" required="true" assignTo="{!nameField}"/>
 <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
 
 <div id="parentDiv"></div>
 
    <style>
     #parentDiv ul:first-child
     {
      padding: 0;
     }
     #parentDiv li
     {
      list-style: none;
      padding: 10px 5px 0 5px;
      position: relative;
     }
  #parentDiv li span 
  {
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      /*border: 1px solid #999;*/
      border-radius: 5px;
      display: inline-block;
      padding: 3px 8px;
      cursor: pointer;
  }
  .selectedRecord
  {
   font-weight:bold; 
   color:blue;
  }
    </style>
    <script>
      var accountMap = JSON.parse('{!jsonMapString}');
      var accountValueMap = JSON.parse('{!jsonMapsobjectString}');
      var cClass = '';
  if("{!topParentId}".indexOf('{!$CurrentPage.parameters.id}') != -1)
   cClass = 'selectedRecord';
  var ul = '<ul><li id="{!topParentId}"  ><span class="' + cClass + '"  onclick="toggleChilds(\'' + '{!topParentId}' + '\',event)" ><b id="i{!topParentId}" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' +  accountValueMap['{!topParentId}'].{!RepersenterField} + '</span></li></ul>'  ;
  $(ul).appendTo("#parentDiv");
  appendUl('{!topParentId}','{!topParentId}');
      function appendUl(key)
      {
       $.each( accountMap[key], function( index, value ) 
       {
      var dclass = '';
      if(value.indexOf('{!$CurrentPage.parameters.id}') != -1)
       dclass = 'selectedRecord';
      var ul = '<ul class="' + key + '"><li id="' + value + '" ><span class="' + dclass + '" onclick="toggleChilds(\'' + value + '\',event)" ><b id="i' + value + '" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' + accountValueMap[value].{!RepersenterField} + "</span></li></ul>"  ;
      $(ul).appendTo("#" + key);
      if(value)
       appendUl(value);
   });
      }
      function toggleChilds(key,event)
      {
       $('.'+key).toggle('slow');
       $('#i'+key).toggleClass('minus');
       $('#i'+key).toggleClass('plus');
       if($('#i'+key).hasClass("minus")) 
        $('#i'+key).html("-");
         if($('#i'+key).hasClass("plus")) 
             $('#i'+key).html("+");
       event.stopPropagation();
      }
    </script>
</apex:component>

Step 3 : Now create a visualforce page, as shown below.

<apex:page standardcontroller="Account" showHeader="true" sidebar="true">
 <apex:pageblock title="Hierarchy">
  <c:DynamicHierarchyForBlog objectName="Account" FieldName="ParentId" RepersenterField="Name"/>
 </apex:pageblock>
</apex:page>
Open the page in the browser and pass a valid account id and the output will be a collapsible hierarchy as shown below.



This can plot the hierarchy of nth level and of any object. Post as comment if you have any questions.

Happy Coding!!

9 comments:

  1. Very informative blog and very useful article thank you for sharing with us , keep posting learn more about salesforce training,salesforce online training

    ReplyDelete
  2. This is very informative blog and useful article thank you for sharing with us keep posting more details aboutsalesforce training in bangalore,salesforce online training

    ReplyDelete
  3. This is very informative blog and nice article , I really like your technique of writing a blog. I book marked it to my bookmark site list and will be checking back in the near future.Salesforce training, salesforce online training

    ReplyDelete
  4. Nice information about dynamic nth Level hierarchy My sincere thanks for sharing this post and please continue to share this kind of post
    Salesfoce Training in Chennai

    ReplyDelete
  5. Thanks for sharing this. This is really a very informative blog. Nice information regarding salesforce implementation services .This is very helpful for those who want to become a saleforce developer. Keep Posting.

    ReplyDelete
  6. Nice blog..! I really loved reading through this article... Thanks for sharing such an amazing post with us and keep blogging...
    ios app development course
    iphone app training course in bangalore

    ReplyDelete
  7. Nice blog..! I really loved reading through this article... Thanks for sharing such an amazing post with us and keep blogging...
    sap consulting services in usa

    ReplyDelete