How to Implement Custom Search in Salesforce

In Salesforce we have search panel at the top of the page that searches for a particular keyword from all fields of SObjects. But what if we want to implement that same search functionality of our own ? Maybe we need this inside a visualforce page to search and perform some action on selected record, or maybe we need to make search on some particular SObject.

I have created basic Custom Global Search functionality which requires simple configurations to change the SObjects and SObjects fields to search keyword from. For searching the keyword i have used SOQL Query and and that SOQL query is a dynamic Query created on run time.

 

How it Works : In Visualforce Page i have used a Input field to take input from user and a command button that performs search.

<apex:pageBlock title="Search">
   <apex:inputText value="{!account}" style="float:left"/>
   <apex:commandButton action="{!search}"  value="Search" style="float:left" /></apex:pageBlock>

On click of  Search command button i am calling Controller’s Method name “search” as defined in action param of command Button.

 public void search(){
        objectsToSearchFrom();
        String searchingObjects = '';
        for(Integer i=0; i<sObjectsToSearch.size();i++){
            SearchingSObject searchingSObject = sObjectsToSearch.get(i);
            searchingObjects = searchingObjects+searchingSObject.getname()+searchingSObject .getParameters();
            if(i != sObjectsToSearch.size()-1){
                searchingObjects  = searchingObjects+',';
            }
        }
        Search.SearchResults searchResult = Search.find('FIND {'+account+'} IN ALL FIELDS RETURNING '+searchingObjects) ;
        boolean isContainRecords = false;
        for(SearchingSObject obj : sObjectsToSearch){
            if(searchResult.get(obj.getName()).size()>0){
              isContainRecords = true;
            break;
            }
        }
        if(!isContainRecords){
            ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,'No Record Found'));
        }
        for(SearchingSObject sobjectToSearch : sObjectsToSearch){
             List<Search.SearchResult> lRecords = searchResult.get(sObjectToSearch.getName());
             Set<String> recordHeaders = new Set<String>();
             List<SObject> sobjects = new List<SObject>();
             for(Search.SearchResult lRecord : lRecords){
                 String fields = getAllFields(String.valueOf(lRecord.getSObject().getSObjectType()));
                 String[] fieldsArray = fields.split('~');
                 recordHeaders.addAll(fieldsArray);
                 sObjects.add(lRecord.getSObject());
             }
             sObjectToSearch.setObj(sObjects);
             sObjectToSearch.setHeaders(new List<String>(recordHeaders));
        }
     }  

In above piece of code i am calling objectsToSearchFrom method  which creates a list of  SearchingSObject type (What is SearchingSObject? SearchingSObject is a wrapper class created in our controller that wraps the SObject and other required fields that we need to display to user.

 public List<SearchingSObject> objectsToSearchFrom(){
        if(sObjectsToSearch == null){
            sObjectsToSearch = new List<SearchingSObject>();
            sObjectsToSearch.add(new SearchingSObject('Account','(Name)'));
            sObjectsToSearch.add(new SearchingSObject('Contact','(Name,Email,Phone,Title)'));
            sObjectsToSearch.add(new SearchingSObject('Opportunity','(Name)'));
            sObjectsToSearch.add(new SearchingSObject('Lead','(Name,Email,Phone,Title,Company)'));
        }
        return sObjectsToSearch;
    }

Now after we got the Returning objects details we create a dynamic SOQL Query with the returned SearchingSObject records and the input search string.  In case you want to change the returning /searching  objects then you just need to change objectsToSearchFrom method implementation by adding more SearchingSObject objects or by changing the field Names.

Then after that i executed my dynamic SOQL Query and from the result i created records that is to be visible on visualforce page.

 for(SearchingSObject sobjectToSearch : sObjectsToSearch){
             List<Search.SearchResult> lRecords = searchResult.get(sObjectToSearch.getName());
             Set<String> recordHeaders = new Set<String>();
             List<SObject> sobjects = new List<SObject>();
             for(Search.SearchResult lRecord : lRecords){
                 String fields = getAllFields(String.valueOf(lRecord.getSObject().getSObjectType()));
                 String[] fieldsArray = fields.split('~');
                 recordHeaders.addAll(fieldsArray);
                 sObjects.add(lRecord.getSObject());
             }
             sObjectToSearch.setObj(sObjects);
             sObjectToSearch.setHeaders(new List<String>(recordHeaders));
        }

 

And renders the UI. Once the UI gets rendered. My apex:repeat and apex:pageBlockTable components creates the UI for user.  apex:render iterates the returned SObjects to create a section for each SObject with Title as the Object name. Inside apex:repeat i have used apex:pageBlockTable that shows all records of a particular SObject in tabular form.

<apex:repeat value="{!sObjectsToSearch}" var="pObject" id="recordGrid">
       <apex:pageBlock title="{!pObject.name}  ({!pObject.obj.Size})" rendered="{!pObject.obj.size!=0}">
          <apex:pageBlockTable value="{!pObject.obj}" var="record">
              <apex:repeat value="{!pObject.headers}" var="header">
                   <apex:column value="{!record[header]}"/>
              </apex:repeat>
          </apex:pageBlockTable>
        </apex:pageBlock>
        <br/><br/>
     </apex:repeat>

 

Complete Code :

Controller :

public class CustomGlobalSearch {
    public List<List<SObject>> parentObjects{get;set;}
    public String account{get;set;}
    public List<SearchingSObject> sObjectsToSearch{get;set;}   
  
    public void search(){
        objectsToSearchFrom();
        String searchingObjects = '';
        for(Integer i=0; i<sObjectsToSearch.size();i++){
            SearchingSObject searchingSObject = sObjectsToSearch.get(i);
            searchingObjects = searchingObjects+searchingSObject.getname()+searchingSObject .getParameters();
            if(i != sObjectsToSearch.size()-1){
                searchingObjects  = searchingObjects+',';
            }
        }
        Search.SearchResults searchResult = Search.find('FIND {'+account+'} IN ALL FIELDS RETURNING '+searchingObjects) ;
        boolean isContainRecords = false;
        for(SearchingSObject obj : sObjectsToSearch){
            if(searchResult.get(obj.getName()).size()>0){
              isContainRecords = true;
            break;
            }
        }
        if(!isContainRecords){
            ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,'No Record Found'));
        }
        for(SearchingSObject sobjectToSearch : sObjectsToSearch){
             List<Search.SearchResult> lRecords = searchResult.get(sObjectToSearch.getName());
             Set<String> recordHeaders = new Set<String>();
             List<SObject> sobjects = new List<SObject>();
             for(Search.SearchResult lRecord : lRecords){
                 String fields = getAllFields(String.valueOf(lRecord.getSObject().getSObjectType()));
                 String[] fieldsArray = fields.split('~');
                 recordHeaders.addAll(fieldsArray);
                 sObjects.add(lRecord.getSObject());
             }
             sObjectToSearch.setObj(sObjects);
             sObjectToSearch.setHeaders(new List<String>(recordHeaders));
        }
     }  

    public List<SearchingSObject> objectsToSearchFrom(){
        if(sObjectsToSearch == null){
            sObjectsToSearch = new List<SearchingSObject>();
            sObjectsToSearch.add(new SearchingSObject('Account','(Name)'));
            sObjectsToSearch.add(new SearchingSObject('Contact','(Name,Email,Phone,Title)'));
            sObjectsToSearch.add(new SearchingSObject('Opportunity','(Name)'));
            sObjectsToSearch.add(new SearchingSObject('Lead','(Name,Email,Phone,Title,Company)'));
        }
        return sObjectsToSearch;
    }
    
    private String getAllFields(String objectName){
        if(objectName.equals('Account')){
                return 'Name';
         }else if(objectName.equals('Contact')){
                return 'Name~Email~Phone~Title';
         }else if(objectName.equals('Opportunity')){
                return 'Name';      
         }else if(objectName.equals('Lead')){
                return 'Name~Email~Phone~Title~Company';
         }else{
                return '()';
         }
    }

    public class SearchingSObject{
        private String name;
        private String parameters;
        public List<String> headers;
        public List<SObject> obj{get;set;}
        
        public SearchingSObject(){}
        
        public SearchingSObject(String name,String parameters){
            this.name = name;
            this.parameters =  parameters;
        }
        
        public List<SObject> getObj(){
            return obj;
        }
        
        public void setObj(List<SObject> obj){
            this.obj = obj;
        }
        
        public String getName(){
            return name;
        }
        
        public String getParameters(){
            return parameters;
        }
        
        public List<String> getHeaders(){
           return headers;
        }
        
        public void setHeaders(List<String> headers){
            this.headers = headers;
        }
    }
}

Visualforce page :

<apex:page controller="CustomGlobalSearch">
     <div>
       <apex:form >
          <apex:pageBlock title="Search">
              <apex:inputText value="{!account}" style="float:left"/>
              <apex:commandButton action="{!search}"  value="Search" style="float:left" />
          </apex:pageBlock>
       </apex:form>
     </div>
     <br/><br/>
     <apex:pageMessages ></apex:pageMessages>
     <apex:repeat value="{!sObjectsToSearch}" var="pObject" id="recordGrid">
       <apex:pageBlock title="{!pObject.name}  ({!pObject.obj.Size})" rendered="{!pObject.obj.size!=0}">
          <apex:pageBlockTable value="{!pObject.obj}" var="record">
              <apex:repeat value="{!pObject.headers}" var="header">
                   <apex:column value="{!record[header]}"/>
              </apex:repeat>
          </apex:pageBlockTable>
        </apex:pageBlock>
        <br/><br/>
     </apex:repeat>
</apex:page>

 

Screenshots :

 

 

 

 

 

Be the first to comment

Leave a Reply

Your email address will not be published.


*