Inline Visualforce Page Layouts!
Filed under: Configuration, Development, Native Application, New Features, salesforce.com
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
Filed under: Configuration, Development, salesforce.com, Visualforce, X-Squared On Demand
<apex:page standardController="Contact" recordSetVar="Contacts" id="updateOwnerPage">
<apex:form>
<apex:sectionheader title="Change Owner for Contacts"/>
<apex:pageblock mode="edit">
<apex:pagemessages />
<apex:pageblocksection title="Change" columns="1">
<apex:pageblocksectionitem>
<apex:outputlabel for="owner">New Owner</apex:outputlabel>
<apex:inputfield id="owner" value="{!Contact.OwnerId}"/>
</apex:pageblocksectionitem>
</apex:pageblocksection>
<apex:pageblocksection title="Selected Contacts" columns="1">
<apex:pageblocktable value="{!selected}" var="j" bgcolor="#F3F3EC" width="100%"
styleClass="list" rowClasses="dataRow" onRowMouseOver="hiOn(this);" onRowMouseOut="hiOff(this);">
<apex:column>
<apex:facet name="header">Contact Name</apex:facet>
<apex:outputlink value="{!URLFOR($Action.Contact.View, j.id)}">
{!j.FirstName} {!j.LastName}</apex:outputlink>
</apex:column>
<apex:column>
<apex:facet name="header">Account Name</apex:facet>
<apex:outputlink value="{!URLFOR($Action.Account.View, j.Account.id)}">
{!j.Account.Name}</apex:outputlink>
</apex:column>
<apex:column>
<apex:facet name="header">Current Owner</apex:facet>
{!j.Owner.Name}
</apex:column>
</apex:pageblocktable>
</apex:pageblocksection>
<apex:pageblockbuttons location="bottom">
<apex:commandbutton value="Save" action="{!save}"/>
<apex:commandbutton value="Cancel" action="{!cancel}"/>
</apex:pageblockbuttons>
</apex:pageblock>
</apex:form>
</apex:page>
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:
<apex:page standardcontroller="Child__c" Extensions="ChildExtension">
<apex:messages />
<apex:form >
<apex:pageBlock mode="edit" id="thePageBlock">
<apex:pageBlockButtons >
<apex:commandButton value="Save" action="{!save}"/>
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:pageBlockButtons>
<apex:pageblockSection id="ParentList" title="1">
<apex:pageBlockSectionItem >
<apex:outputLabel value="Parent" for="p"/>
<apex:selectList id="p" value="{!Child__c.Parent__c}" size="1" title="3">
<apex:selectOptions value="{!ParentOptions}"/>
</apex:selectList>
</apex:pageBlockSectionItem>
</apex:pageblocksection>
</apex:pageBlock>
</apex:form>
</apex:page>
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.
public class ChildExtension {
private final Child__c child;
public ChildExtension(ApexPages.StandardController controller) {
this.child = (Child__c)controller.getRecord();
}
public List<selectOption> ParentOptions {get
{
List<selectOption> parents = new List<selectOption>();
for (Parent__c prt : [select name from Parent__c pt])
parents.add(new selectOption(prt.id, prt.name));
return parents;
}
private set;
}
}
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
Filed under: Configuration, Development, Native Application
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.





