Showing posts with label template. Show all posts
Showing posts with label template. Show all posts

Monday, April 2, 2012

SObject Utility Class Template

Have you ever had to get the ID of a record type for a specific object? Or have you needed to hard-code a particular picklist value into a Visualforce controller/extension or other Apex class? I've had to do both on a fairly regular basis, and it soon became apparent that stress-related health problems may arise if I ever have to refactor my code, or if a user requests a change in picklist values.

To address this issue, it seems that setting up a global constant accessible to all Apex classes would be hugely valuable in making sure that picklist values and record types (and other items) are consistently referenced in Apex.

For example, if I'm trying to set the Status of a Contract to "Activated", I could write the code as follows:
myContract.Status = 'Activated';

This is great if it's the only place I ever deal with the Contract Status field. But what're the chances of that? Instead, how about writing the code as follows?
myContract.Status = ContractUtil.ACTIVATED_STATUS;

Now I don't need to worry about all the myriad places where I've hardcoded the status value. If I ever need to change the status, I can update the constant in ContractUtil or look for all references to ContractUtil.ACTIVATED_STATUS.

Here's the sample code for a generic SObject utility class:
/**
 * Utility class with supporting methods for
 * a Salesforce SObject.
 *
 * Examples of supporting methods include getting
 * a Record Type ID, getting an expected picklist
 * value for a particular field, and conversion
 * to/from other objects.
 */
public class GenericSObjectUtil {

    /**
     * The String value that
     * represents an activated status, which goes
     * into the Status field.
     */
    public static final String ACTIVATED_STATUS =
            'Activated';

    /**
     * The expected default Record Type Name
     * for all users.
     */
    public static final String DEFAULT_RECORD_TYPE_NAME =
            'This SObject';

    /**
     * The String value that
     * represents a draft status, which goes
     * into the Status field.
     */
    public static final String DRAFT_STATUS =
            'Draft';

    /**
     * The map of RecordTypeInfo
     * objects retrieved by describing the
     * SObject, keyed by the Record Type Name.
     * 
     * This is stored to make
     * getRecordTypeId method calls
     * more efficient.
     */
    private static final Map recordTypeInfosByName =
            Schema.SObjectType.Contract.getRecordTypeInfosByName();

    /**
     * Retrieve the Record Type ID based on a
     * given Record Type Name.  If no match is
     * found, then return null.
     *
     * @param  name The name of the Record Type
     * @return      The ID of the Record Type,
     *              if found; null otherwise.
     */
    public static Id getRecordTypeId(String name) {
        return recordTypeInfosByName.get(name).getRecordTypeId();
    }   // public static Id getRecordTypeId(String)
}   // public class GenericSObjectUtil

Note: I know the above code may be cut off a bit due to width limits in Blogger, but you should be able to copy and paste the code into a text editor to see the full structure if necessary.

What do you think? Feedback on this implementation or other solutions will be appreciated!

Saturday, August 20, 2011

Merge Field Functions in Email Templates

This may help to get people thinking about how much can be accomplished with text and HTML email templates before diving into Visualforce templates.

Did you know that you can substitute in text for blank values? By using the {!sObject.FieldName, substitute text including spaces} convention, blank values can be automatically replaced with default values.

Furthermore, it looks like at the email templates recognize at least two Visualforce-esque functions, demonstrated in the following examples:
  • {!NullValue(Lead.Name,"visitor")}, which is the same as the substitution described above
  • {!If(Lead.Name="Barack Obama","President","Citizen")}
  • {!If(IsPickVal(Lead.Status,"New"),"Super Important","Somewhat Important")}
Does anyone have any other information on what functions can be used in simple text or HTML email templates? Are all Visualforce functions available here, I wonder?

Friday, July 15, 2011

Lead and Contact Merge Fields in Email Templates

Interesting note about Lead and Contact merge fields in Salesforce email templates: Some of the fields will populate regardless of whether the record is of the correct type.

For example, in my template, the first line read:
Dear {!Contact.FirstName}{!Lead.FirstName},

I figured that only one of the two fields would actually produce the target's first name. However, when I actually tested the merge fields in Salesforce with a Contact record and with a Lead record, in both instances the result read:
Dear JohnJohn,

Interestingly, this duplicate merge did not occur in the signature, where I had the following:
Sincerely,
{!Contact.OwnerFullName}{!Lead.OwnerFullName}

In the signature, only the relevant OwnerFullName field was populated, depending on whether a Contact or a Lead was selected.

I wonder whether this phenomenon is intentional or indicative of a bug...

Friday, May 27, 2011

JavaScript Hack to Add All Fields to Export Template

Faced with the daunting task of creating an export template in ApplyYourself that included all available fields, I decided to try my luck at using JavaScript to do the job for me (with greater accuracy).

The end result is the following hack, which adds all exposed nodes to the template.
javascript:

/* Grab the fields frame. */

var fieldsFrame =
    document.getElementsByName(
        "frameQuestionsTree")[0];
var fieldsWindow = fieldsFrame.contentWindow;
var fieldsDocument = fieldsWindow.document;

/* Grab the actions frame. */

var actionsFrame =
    document.getElementsByName(
        "frameActions")[0];
var actionsWindow = actionsFrame.contentWindow;
var actionsDocument = actionsWindow.document;

/* Find the exposed nodes to add. */

var fieldsATags = fieldsDocument.getElementsByTagName("a");
alert(fieldsATags.length + " A tags found in fields window.");

var nodeIdPattern = /Nod[0-9]+/;
var nodeATags = new Array();
for (var i = 0; i < fieldsATags.length; i++) {
  var fieldsAElem = fieldsATags[i];
  var fieldsAIdAttr = fieldsAElem.attributes["id"];
  if (fieldsAIdAttr) {
    if (fieldsAIdAttr.value.match(nodeIdPattern)) {
      var nodeNumText = fieldsAIdAttr.value.slice(3);
      fieldsWindow.setSelectedNode(parseInt(nodeNumText));
      actionsWindow.BtnAddField_onclick();
    }
  }
}
This hack was tested in...
  • Chrome 11 on Windows 7
  • Internet Explorer 9 on Windows 7

Saturday, March 19, 2011

apex:define Tag Precedence in Visualforce Templates

I learned something interesting through trial-and-error yesterday:

If you define a set of templates where each successive template "extends" the previous template, the apex:insert tag in all previous templates are available for definition in the final implementing page.

For example, let's take take the following hierarchy of templates:
  1. SiteMasterTemplate
  2. SiteDepartmentTemplate--contains an apex:composition with template="SiteMasterTemplate"
  3. SiteProductTemplate--contains an apex:composition with template="SiteDepartmentTemplate"

Now, if we create a page called SiteSuperMotor that contains an apex:composition with template="SiteProductTemplate", our page can actually use apex:define that define apex:insert elements in SiteMasterTemplate!

Furthermore, let's say that we have apex:insert elements in both SiteDepartmentTemplate or SiteProductTemplate that share the same name attribute as an apex:insert in SiteMasterTemplate, then the SiteSuperMotor page's apex:define would only define the apex:insert in SiteMasterTemplate!