Custom Error Handling in Visualforce
I am a big fan of developing Visualforce pages that are useful to humans. This means providing helpful feedback to the person interacting with the application in order to limit User frustration. In some circumstances this means providing clearer error messaging rather than simply outputting any system generated errors.
In this example we are going to create a custom search page allowing Users to query Contacts by providing a search term. To provide the most flexibility we will allow searching with wildcard characters. We will be using the FIND clause in our SOSL query behind the scenes to make this functionality work.
Before we get started I want to highlight two items that we need to keep in mind as we begin to build out the application. First, FIND requires that we provide at least two characters in order to run the query. Second, in the situation where a wildcard is provided, we need to make sure that there are two non-wildcard characters in addition to the wildcard.
Now that we are aware of these two items we can build out our controller logic for the page.
/*
Created by: Greg Hacic
Last Update: 31 August 2015 by Greg Hacic
Questions?: greg@interactiveties.com
Notes:
- controller for errorHandlingSample.page
*/
public with sharing class errorHandlingSample {
public List<Contact> contactRecords = new List<Contact>(); //list for Contact records
public String searchError; //variable for housing the error text
public String searchString {get; set;} //the input provided by the User as they interact with the Visualforce page
//constructor
public errorHandlingSample() {
performSearch(); //call the performSearch method
}
//getter for the searchError variable
public String getSearchError() {
return searchError; //return searchError value
}
//method for searching based upon the search string provided from the user interface
public void performSearch() {
contactRecords.clear(); //clear the current list
searchError = null; //null out the search error string
if (searchString != '' && searchString != null) { //if searchString is not null
if (searchString.length() >= 2) { //if searchString has more than 1 character
if ((searchString.contains('*') || searchString.contains('?')) && searchString.length() < 3) { //if searchString is less than 3 characters long and contains a wildcard value
searchError = 'Three characters are required when using wildcards in your search.'; //provide an error message so the User may revise their search
}
} else { //otherwise, the searchString is less than 2 characters long
searchError = 'You must include at least two characters in the search string.'; //provide an error message so the User may revise their search
}
if (searchError == null) { //if searchError is null
List<List<sObject>> searchList = [FIND :searchString IN ALL FIELDS RETURNING Contact(AccountId, Account.Name, Id, Email, MobilePhone, Name, Phone, Title ORDER BY LastName)]; //search for all contacts
List<Contact> listOfFoundContacts = ((List<Contact>)searchList[0]); //cast the search results into a list of Contacts
for (Contact c : listOfFoundContacts) { //for all Contacts returned in our search
contactRecords.add(c); //add the Contact to our contactRecords list
}
}
}
}
//getter for the list of Contacts
public List<Contact> getContactRecords() {
return contactRecords;
}
//getter for the size of the list of Contacts
public Integer getContactRecordsSize() {
return contactRecords.size();
}
}
What you'll notice first about the above controller is, rather than relying on the system to throw an error, we are using an error string variable (searchError) to denote when we encounter issues for which we are coding. We will use this variable in our Visualforce page and if the value is null we will show a table of records from our search results. When the value is not null we will show an error message instead of table of results. See the code for our page below:
<apex:page controller="errorHandlingSample" docType="html-5.0" showHeader="true" sidebar="true" standardStylesheets="true">
<!--
Created by: Greg Hacic
Last Update: 31 August 2015 by Greg Hacic
Questions?: greg@interactiveties.com
-->
<apex:sectionHeader title="Search" subtitle="Contacts"></apex:sectionHeader>
<p>This is a Visualforce example illustrating how to handle errors in a more granular manner. Try searching for <b>g*</b> or <b>g</b> to see the error messaging.</p>
<apex:pageMessages></apex:pageMessages>
<apex:form>
<div style="margin: 25px;">
Filter:
<apex:inputText id="searchString" size="25" title="name of company, contact, city, state, zip code" value="{!searchString}"></apex:inputText> <!-- input field -->
<apex:commandButton action="{!performSearch}" id="runContactSearch" rerender="searchResultsArea" status="requestStatus" value="Search"></apex:commandButton> <!-- search button -->
</div>
<apex:actionStatus id="requestStatus"><!-- component that displays the status of an AJAX request -->
<apex:facet name="start"> <!-- placeholder for content that's rendered when the AJAX request is started -->
<apex:image url="/img/loading.gif" alt=" Loading... "></apex:image> <!-- a rotating .gif image -->
</apex:facet>
<apex:facet name="stop"> <!-- placeholder for content that's rendered when the AJAX request is finished -->
<apex:outputPanel id="searchResultsArea" layout="block">
<apex:outputPanel rendered="{!searchError != null}"> <!-- error messaging area rendered whenever the searchError variable is not null -->
<div class="message errorM2"> <!-- standard styling that Salesforce uses throughout the platform we are just adopting it here -->
<table border="0" cellpadding="0" cellspacing="0" class="messageTable" style="padding: 0px; margin 0px;">
<tr valign="top">
<td><img src="/s.gif" class="msgIcon" title="" /></td> <!-- standard Salesforce warning graphic -->
<td class="messageCell"><div class="messageText">{!searchError}</div></td> <!-- the place where we render any searchError value from the controller -->
</tr>
</table>
</div>
</apex:outputPanel>
<apex:outputPanel rendered="{!AND( NOT( searchError != null), contactRecordsSize < 1 )}"> <!-- informational messaging area rendered when there are no results from the search -->
<div class="message infoM2"> <!-- standard styling that Salesforce uses throughout the platform we are just adopting it here -->
<table border="0" cellpadding="0" cellspacing="0" class="messageTable" style="padding: 0px; margin 0px;">
<tr valign="top">
<td><img src="/s.gif" class="msgIcon" title="" /></td> <!-- standard Salesforce informational graphic -->
<td class="messageCell"><div class="messageText">Your search yields no results...</div></td>
</tr>
</table>
</div>
</apex:outputPanel>
<apex:pageBlock rendered="{!contactRecordsSize > 0}" title="Results">
<apex:pageBlockTable cellpadding="2" cellspacing="2" value="{!contactRecords}" var="c" width="100%">
<apex:column>
<apex:facet name="header">Name</apex:facet>
<a href="/{!c.Id}">{!c.Name}</a>
</apex:column>
<apex:column value="{!c.Title}" />
<apex:column value="{!c.AccountId}" />
<apex:column value="{!c.Email}" />
<apex:column value="{!c.MobilePhone}" />
<apex:column value="{!c.Phone}" />
</apex:pageBlockTable>
</apex:pageBlock>
</apex:outputPanel>
</apex:facet>
</apex:actionStatus>
</apex:form>
</apex:page>
You may also notice that we are including the apex:pageMessages tag in our page in order to catch system errors that we may not have coded for.