Inline Visualforce Page Layouts!
We’re all used to using inline S-Controls, dragging and dropping them into page layouts. And the entire Salesforce community has been spending tons of time recreating page layouts in Visualforce, just to edit one small piece of a page.
As an example, how would you implement the example at developer.force.com: Visualforce Dynamic Edit Page? You would do it the way it was explained in the blog post!
Well the rules of the game have changed.
As long as you use a Standard Controller, you can now place Visualforce pages IN regular page layouts!
Inline Visualforce Page Layout screenshot
The article was written by Sati Hillyear, who is also an expert on the License Manager Application. Check it out!
[Addendum 5-9-2009: For another example of this, see Jeff Douglas' blog post.]
Project: Change Owner Button in Visualforce
Salesforce Labs has put out a series of Mass Action packages on the AppExchange. There is Mass Transfer Opportunity Owner (uses AJAX), Mass Update Contact Addresses (AJAX), Mass Update Opportunity Owner, Mass Update Opportunity Close Dates, etc. All of these are “thick client” tools, meaning that data must be loaded onto your computer, altered, and then uploaded back to Salesforce.
Ron Hess released a super bit of code, found in the Visualforce documentation and elsewhere, to Mass Update Opportunity Stage and Close Date. It could, theoretically, be expanded to other fields as well. This got me thinking about doing so with other objects.
A while ago, I took the code for the Mass Delete button and altered it to change the owner of the selected records to the User clicking the button. It was like an Accept button, but I could use it for any object. Actually, it wasn’t as easy as that. I had to make one button for each object, and maintenance was a pain–whenever I created a new object, I needed to clone my code.
Drawing upon some code I found in the Developers Guide, I have written a Visualforce page to mass-change the owner of all selected records to any active User in Salesforce. Yes, it only works with Contacts for now, but my next step will be to use Dynamic Apex to pass the sObject name to the page and its extension/controller, allowing me to reuse one bit of code for multiple objects. We’ll see how it goes. But in the meantime, enjoy this page that lets you perform a search, check which records you want to transfer, and then input a User. I’ve tested it with 50 records at once, so that should suffice for most uses.
VF Page:
<br />
<apex:page standardController="Contact" recordSetVar="Contacts" id="updateOwnerPage"><br />
<apex:form><br />
<apex:sectionHeader title="Change Owner for Contacts"/><br />
<apex:pageBlock mode="edit"><br />
<apex:pageMessages /><br />
<apex:pageblockSection title="Change" columns="1"><br />
<apex:pageblockSectionItem ><br />
<apex:outputLabel for="owner">New Owner</apex:outputLabel><br />
<apex:inputField id="owner" value="{!Contact.OwnerId}"/><br />
</apex:pageblockSectionItem><br />
</apex:pageBlockSection><br />
<apex:pageBlockSection title="Selected Contacts" columns="1"><br />
<apex:pageBlockTable value="{!selected}" var="j" bgcolor="#F3F3EC" width="100%"<br />
styleClass=”list” rowClasses=”dataRow” onRowMouseOver=”hiOn(this);” onRowMouseOut=”hiOff(this);”><br />
<apex:column ><br />
<apex:facet name="header">Contact Name</apex:facet><br />
<apex:outputLink value="{!URLFOR($Action.Contact.View, j.id)}"><br />
{!j.FirstName} {!j.LastName}</apex:outputLink><br />
</apex:column><br />
<apex:column ><br />
<apex:facet name="header">Account Name</apex:facet><br />
<apex:outputLink value="{!URLFOR($Action.Account.View, j.Account.id)}"><br />
{!j.Account.Name}</apex:outputLink><br />
</apex:column><br />
<apex:column><br />
<apex:facet name="header">Current Owner</apex:facet><br />
{!j.Owner.Name}<br />
</apex:column><br />
</apex:pageBlockTable><br />
</apex:pageblockSection><br />
<apex:pageBlockButtons location="bottom"><br />
<apex:commandButton value="Save" action="{!save}"/><br />
<apex:commandButton value="Cancel" action="{!cancel}"/><br />
</apex:pageBlockButtons><br />
</apex:pageBlock><br />
</apex:form><br />
</apex:page><br />
Button:
Go to Setup -> Contact -> Buttons and Links
Create a new button, set it to execute in the current window with sidebar and header, and set it to call a Visualforce page. Select the page you just created. Then add the button to Contact Search Layout and to any Contact related lists you like.
Voila!
Project: Lookup to Picklist
In the first installment of post-Dreamforce projects, I present a mechanism to present the user with all available Lookup options in a picklist. This should simplify some Visualforce pages. (Credit to the Developers Guide from the new post-Dreamforce Library.)
The key to the code is the ability to customize the SOQL statement to focus as much, or as little, as the developer would like. Though the code I provide makes no limit on the number of records returned, I encourage developers to limit the select statement as seen fit.
VF Page:
<br />
<apex:page standardcontroller="Child__c" Extensions="ChildExtension"><br />
<apex:messages ></apex:messages><br />
<apex:form ><br />
<apex:pageBlock mode="edit" id="thePageBlock"><br />
<apex:pageBlockButtons ><br />
<apex:commandButton value="Save" action="{!save}"/><br />
<apex:commandButton value="Cancel" action="{!cancel}"/><br />
</apex:pageBlockButtons><br />
<apex:pageblockSection id="ParentList" title="1"><br />
<apex:pageBlockSectionItem ><br />
<apex:outputLabel value="Parent" for="p"/><br />
<apex:selectList id="p" value="{!Child__c.Parent__c}" size="1" title="3"><br />
<apex:selectOptions value="{!ParentOptions}"/><br />
</apex:selectList><br />
</apex:pageBlockSectionItem><br />
</apex:pageblocksection><br />
</apex:pageBlock><br />
</apex:form><br />
</apex:page><br />
Extension:
Note the SOQL query in Line 12 (below) that defines which records are included in the picklist. You can include WHERE and LIMIT statements to get the picklist down to a manageable number of items.
<br />
public class ChildExtension {</p>
<p>private final Child__c child;</p>
<p> public ChildExtension(ApexPages.StandardController controller) {<br />
this.child = (Child__c)controller.getRecord();<br />
}</p>
<p> public List<br />
<selectOption> PositionOptions {get<br />
{<br />
List<br />
<selectOption> parents = new List<br />
<selectOption>();<br />
for (Parent__c prt : [select name from Parent__c pt])<br />
parents.add(new selectOption(prt.id, prt.name));<br />
return parents;<br />
}<br />
private set;<br />
}<br />
}<br />
Because the parents List in the extension sends an ID to the application, it can successfully create a record with the parent Name in the picklist, but the ID in the background. You can also substitute a different field for Name: If you prefer, put a contact’s email address or anything else. Try it out!
One more thing: This is an easy segue into another project, which will be a way to use the traditional lookup interface but to pre-filter the records available in the lookup.
And because I put this in every post: There’s a catch. (There always is.) I’m sure that somewhere in there, Salesforce would prefer that we not create a picklist of a few hundred items. So please feel free to test the limits of this visualforce method, but please be prepared to filter your SOQL query.
On a separate note, I just had lunch with John Rotenstein aka The Enforcer, who already put up a photo of our time in his office. (I think the pirate logo was an accident, but it does add to my sinister persona, no?)
Salesforce Order of Execution
I came across this page in the Apex documentation and wanted to share it with everyone. So many people have asked about this in the past, so it seems a good idea to publicize it:
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_order_of_execution.htm
Triggers and Order of Execution
When a record is saved with an insert, update, or upsert statement, the following events occur in order:
1. The original record is loaded from the database (or initialized for an insert statement)
2. The new record field values are loaded from the request and overwrite the old values
3. All before triggers execute
4. System validation occurs, such as verifying that all required fields have a non-null value, and running any user-defined validation rules
5. The record is saved to the database, but not yet committed
6. All after triggers execute
7. Assignment rules execute
8. Auto-response rules execute
9. Workflow rules execute
10. If there are workflow field updates, the record is updated again
11. If the record was updated with workflow field updates, before and after triggers fire one more time (and only one more time)
12. Escalation rules execute
13. All DML operations are committed to the database
14. Post-commit logic executes, such as sending email
Additional Considerations
Please note the following when working with triggers:
* When Enable Validation and Triggers from Lead Convert is selected, if the lead conversion creates an opportunity and the opportunity has Apex before triggers associated with it, the triggers run immediately after the opportunity is created, before the opportunity contact role is created. For more information, see “Customizing Lead Settings” in the Salesforce online help.
* If you are using before triggers to set Stage and Forecast Category for an opportunity record, the behavior is as follows:
o If you set Stage and Forecast Category, the opportunity record contains those exact values.
o If you set Stage but not Forecast Category, the Forecast Category value on the opportunity record defaults to the one associated with trigger Stage.
o If you reset Stage to a value specified in an API call or incoming from the user interface, the Forecast Category value should also come from the API call or user interface. If no value for Forecast Category is specified and the incoming Stage is different than the trigger Stage, the Forecast Category defaults to the one associated with trigger Stage. If the trigger Stage and incoming Stage are the same, the Forecast Category is not defaulted.
Upcoming Plans
This is my first blog post since Dreamforce 2008, and I had an amazing time. Hello to everyone I met, and hello to all the people that I said I’d meet – but couldn’t. I left Dreamforce and came to Sydney to visit my family, and am writing this blog post sitting on a deck chair under a setting sun, listening to my niece and nephew play nicely.
This blog post is partly an announcement of X-Squared’s upcoming plans and projects, and partly a way to hold myself to my word. It is said that while managing the Yankees, Joe Torre tried to quit many times, until someone bet him $1000 that he couldn’t quit… and told everyone he knew about the bet. Clearly, $1000 is small change to Torre, but the pressure of the whole world knowing his plan to quit helped him quite a bit. So here is X-Squared On Demand’s list of projects and plans (outside of the standard billing work for our amazing clients):
Jon Mountjoy suggested that I pick one Salesforce development feature and learn it completely instead of making the mistake of trying to learn everything and doing it all poorly. I chose Visualforce. All my side projects from now on will involve Visualforce to some degree.
- Lookup to Picklist: I’ve always been interested in lookup fields and have written some interesting implementations that use error messages and custom buttons to simplify and focus allowed values for lookups. Here, I plan to present the user with a list of all the target records available and to present them in a picklist. (Of course, if there are more than 50 records, I will leave the field as a lookup.)
- Filtered Lookup: I have the code for a filtered lookup that utilizes a three-page wizard to choose the proper record for a lookup, but I want to simplify this to allow an administrator to limit a lookup to one Record Type or any other hard-coded filter. Then I’ll use a simplified wizard to enhance that feature, which would basically be like using the lookup filters in Enhanced Lookups currently available in the standard UI.
- NonProfit EventForce using Google Sites: We started this project at Dreamforce 2008, and I have a non-profit client who would like a tool to allow registration for various kinds of events. This is a super opportunity to expand upon this hackathon project. Colin Loretz has agreed to help on this, and Steve Wright of Salesforce.com Foundation has offered to provide a salesforce.com technical resource if we make the code open-source. I told Steve that in my mind I was writing the code for the Foundation, and that the Foundation could do whatever it wanted with the code. So keep an eye out for this in the next month or two.
- Airport Codes to Full Name of the airport when entered into a field, using Visualforce.
- SIC to NAICS: I have NO idea why Salesforce CRM is so attached to SIC codes–after all, the government has completed its changeover to NAICS codes. I plan to use the existing conversion charts provided by the government to allow orgs to convert their data from SIC to NAICS.
- Google Maps as a Data Enrichment Tool: Input the ZIP Code, and Google Maps will return a city/state. Or input the Street and City/State, and Google Maps will return the ZIP Code. Sorry, DemandTools and Postcode Anywhere, this might cut into your profit margin.
- Drop.io for AppExchange: I love drop.io as a file sharing and storage tool, and with the release of their API–and Ron Hess’s explanation of his XMLDom Apex Class, it may be time to create a nice app allowing 100MB of storage per record in Salesforce CRM. It might require a couple of hacks before it can be used for more than standard objects, but this will likely be my ongoing work in progress.
- Use Amazon EC2 Windows to put the Workbench in the Cloud.
- And finally, I will spend the next year making a list of everyone I want to meet at Dreamforce 2009, and will find a way to see everyone there!
There are probably many more ideas sketched on napkins and pads of paper around my office, but this is a beginning list of projects I’m most passionate about. If anyone would like to help with any, please let me know!


