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 :
Leave a Reply