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