Dynamically Updating Probability When Selecting Stage with Visualforce
Clicks, clicks, and more clicks! Everyone wants the computer to do the work, clicking the mouse is just too hard! So let’s make the UI in our Salesforce org shoulder some of the work for our customer. Here I’ll describe how to use a Visualforce actionSupport tag to automatically populate the Opportunity probability percentage value when the customer selects a StageName from a picklist.
First lets look at the objects we are working with: Opportunity and OpportunityStage. The sales and marketing folks tell us that Opportunities have distinct Stages. As they progress through each Stage, chatting up a prospective client, the chance of landing the Opportunity increases, such that if they make it to negotiating the contract they have a 90% probability of successfully turning the Opportunity into a Contract. So they say. There are 10 default Stage values for a Salesforce org are shown below:
We can represent the Probability with a Visualforce inputField and have our customer type it in, but here we will do the work for them.
First the Visualforce. Here is a snippet of a page with an apex:inputField for the Stage Name and another apex:inputField for the Probability:
1 <table> 2 <tr> 3 <th>Opportunity Name</th> 4 <td><apex:inputField value="{!thisOpp.Name}" /></td> 5 </tr> 6 <tr> 7 <th>Opportunity Stage</th> 8 <td> 9 <apex:actionRegion > 10 <apex:inputField value="{!thisOpp.StageName}" > 11 <apex:actionSupport event="onchange" action="{!changeStageName}" 12 rerender="probability,messages" /> 13 </apex:inputField> 14 </apex:actionRegion> 15 </td> 16 </tr> 17 <tr> 18 <th>Probability (%)</th> 19 <td> 20 <apex:inputField value="{!thisOpp.Probability}" id="probability" /> 21 </td> 22 </tr> 23 </table>
The Stage Name will be rendered in the browser as a picklist. The Probability is rendered as a text input:
We use an apex:actionSupport tag to invoke the changeStageName method in our controller when the picklist value changes. Notice the rerender on line 12. We don’t want the whole Visualforce page to reload. If there are other dynamic elements then managing their interactions can get very complex. We wrap an apex:actionRegion around the picklist so that only the picklist value is submitted to the server. Once again, if this is part of a large complex page with other dynamic elements we probably do not want them all updating with each change. For example, this could cause a problem if the form needs to be validated only when the entire form is saved.
Now let’s look at the Apex code in the controller. The actionSupport element action changeStageName is bound to an identically name method in the controller:
1 // The user changed the Opportunity StageName. Set the Probability to the 2 // correct value, based on the defaults set up in the OpportunityStage object. 3 public transient Map<String, Decimal> probabilityStageNameMap; 4 5 public PageReference changeStageName() { 6 7 if (probabilityStageNameMap == null) { 8 probabilityStageNameMap = new Map<String, Decimal>(); 9 for (OpportunityStage oppStage : [Select MasterLabel, DefaultProbability 10 From OpportunityStage]) { 11 probabilityStageNameMap.put(oppStage.MasterLabel, oppStage.DefaultProbability); 12 } 13 } 14 15 if (probabilityStageNameMap.containsKey(thisOpp.StageName)) { 16 thisOpp.Probability = probabilityStageNameMap.get(thisOpp.StageName); 17 } 18 19 return null; 20 }
We only create a Map of StageName to probability once, the first time this method is invoked as you can see on line 3. Also, notice we return null – we are not navigating to a new page, we are just quietly updating one field:
The end result is that your customer selects a StageName from a picklist and automagically the percentage field is populated. Your customer can manually input a different Probability percentage value if they choose, but more than likely they want the default value and they don’t want the extra clicking and typing. The use of dynamic elements like this will make your interface faster to use and more engaging to your customers.