11 May 2011

Parameterized Custom Label

I still remember when custom labels where new and I have a requirement in which I wanted to create a VF email template in which non technical people wouldn't need to edit VF pages to update the email content.

Custom labels first came to mind. However, I thought that multiple custom labels will do the work in which I will concatenate each of them included values I wanted to insert in between words. Then I found out that this is not the best approach as SFDC impose limits to the number of custom labels per org.

Then I found what I'm looking for. It turns out that I can add parameter to custom labels and use the <apex:param> tag to update the value of the parameter in custom labels. To make the story short I created a sample for this entry.

First we create a custom label similar to this:


Take note of the values denoted by the curly braces and the number inside of it. This values empowers the custom labels to accept parameters. Also, you noticed that it start with the number 0. This is the default, as the first parameter you will add on your VF pages <apex:outputText> or any tags that will be displayed on that merge field (I'm calling it merge field).

Next we create a simple VF email template.


For the purpose of this example, I just created an email template that uses the recipientType and relatedToType to Contact. Basically I used the <apex:outputText> tag and add the custom label as its value. Then inside the <apex:outputText> tag, I added some <apex:param> tags with values. Note that the first param tag will be the value for the {0} merge field.

When you save the VF email template you will instantly see that the parameters was substituted by the values you added on the tags.

That's it. You have used parameters for your custom labels!

14 April 2011

How to Process Record using List Button and Visualforce

Long ago, if we want to process records from a record list we create a list button that executes a javascript. The javascript would then use the Salesforce AJAX Toolkit and use a merge field called GETRECORDIDS. However this proved to be slow since its running in client side.

The best way to workaround this is to use Visualforce and the StandardSetController.

Let's say for example that we wan't to update a set of contact via a button on the contact list. First we need to create a Visualforce page that uses its standard controller and creating an extension class.

So for example, we create a Visualforce page with the name ContactListUpdate similar to this:

<apex:page standardController="Contact" 
  extensions="ContactListUpdateExtension" 
  recordSetVar="c" action="{!updateContacts}">
    <apex:form >
        <apex:pageMessages />
        <apex:pageBlock >
            <apex:pageBlockButtons >
                <apex:commandButton value="Back" 
                                 action="{!returnPage}"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1">
                The selected contacts were updated. 
                                Please click the back button to return 
                                to the previous page.
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Take note of the 'RecordSetVar' attributes. Since we will be using the StandardSetController on our controller extension, then it is required.

Then we create our controller extension:

public class ContactListUpdateExtension {
  static string SECONDARY_CONTACT = 'Secondary';
  Contact[] arryContact;
  PageReference pgReturnPage;
  
  // Constructor
  public ContactListUpdateExtension(ApexPages.StandardSetController 
                                   cntlr){
    arryContact = cntlr.getSelected();
    
    // Build the return page 
    String returnUrl = ApexPages.currentPage().
      getParameters().get('retUrl');
    pgReturnPage = new PageReference(returnUrl);
        pgReturnPage.setRedirect(true);
  } 
  
  public void updateContacts(){
    List<Contact> lstContactUpdate = new List<Contact>();
    
    for(Contact c: arryContact){
      c.Level__c = SECONDARY_CONTACT;
      lstContactUpdate.add(c);
    }
    
    Database.Saveresult[] arryResult = 
       Database.update(lstContactUpdate);
    for(Database.SaveResult sResult : arryResult){
      if(!sResult.isSuccess()){
        Database.Error errMsg = sResult.getErrors()[0];
        ApexPages.addMessage(
           new ApexPages.Message(
              ApexPages.Severity.ERROR,
              errMsg.getMessage()));
      }
    }
  }
  
  public PageReference returnPage(){
    return pgReturnPage;
  }
}

In this example I am updating the contacts custom field Level__c to a value 'Secondary'.

As you can see, the constructor parameter accepts the ApexPages.StandardSetController type. This will help us access the selected records by accessing the getSelected() property.

We can now create a List Button whose content source = 'Visualforce page' and refer the previously created Visualforce page. You must also note that we want to have user the ability to select multiple records so we need to tick the 'Display Checkboxes (for Multi-Record Selection)' checkbox.




That's it. You are now processing multiple records on a List Button using Visualforce. Note that you need to add this button to its appropriate page layouts.

31 March 2011

Adding a checkbox on a PageBlockTable

One of the common use cases I experienced developing customization in Salesforce is the ability for end user to selected multiple records from a list and process them. In Salesforce you can do this via client-side scripting using JavaScript. However, it is slow and you don't really have full control of the selected records specially when your doing multi-paging list.

The best approach I believed on doing this is to create an Apex wrapper class. The wrapper class is a class that will represent data for your table with additional properties. An example of using wrapper class is when you want to display an accounts and then select them using a checkboxes. Let's see how we approach that below.

We first create a wrapper class similar to this:

public class AccountWrapperCls {
     public Boolean isSelected {get;set;}
     public Account cAccount {get;set;}

     public AccountWrapperCls(Account cAccount){
          this.cAccount = cAccount;
     }
}

As you can see above, the class contains an account and a boolean property. The isSelected property will be referenced by our Visualforce page and will be rendered as a checkbox. To use this wrapper class we need to create a Visualforce controller for our page that will use the class above.

public class MyAccountListCntrlr {
     // PROPERTIES
     public List<AccountWrapperCls> acctList {get;set;}
     public Set<String> selAccountNames {get;set;}
     public Boolean hasSelAcct {get;set;}

     // CONSTRUCTOR
     public MyAccountListCntrlr(){
          acctList = new List<AccountWrapperCls>();
          selAccountNames = new Set<String>();

          for(Account a : [SELECT AccountNumber, Name 
          FROM Account WHERE AccountNumber != NULL 
          LIMIT 5]){
               acctList.add(new AccountWrapperCls(a));
          }
     }

     // METHODS
     public void displaySelectedAccountNumbers(){
          selAccountNames.clear();
          hasSelAcct = false;
          for(AccountWrapperCls cWrapper : acctList){
               if(cWrapper.isSelected){
                    hasSelAcct = true;
                    selAccountNames.add(cWrapper.cAccount.
                             AccountNumber);
               }
          }
     }
}

As you can see above, we created a list of type AccountWrapperCls which represents the account record and the additional isSelected property. Please note that we add a method called displaySelectedAccountNumbers() which gets all the account records whose isSelected value is set to TRUE. It also adds those selected account's account number to a set variable we defined in our class which we will use to display account numbers on the page.

Below is our Visualforce page:

<apex:page controller="MyAccountListCntrlr" tabStyle="Account">
   <apex:form >
      <apex:pageBlock title="Account List">
         <apex:pageBlockButtons >
            <apex:commandButton 
               value="Show Selected Accounts" 
               action="{!displaySelectedAccountNumbers}"/>
         </apex:pageBlockButtons>

         <!-- ACCOUNT LIST -->
         <apex:pageBlockTable 
           value="{!acctList}" 
           var="acctWrapper">
            <apex:column >
               <apex:inputCheckbox 
                 value="{!acctWrapper.isSelected}"/>
            </apex:column> 
            <apex:column 
              value="{!acctWrapper.cAccount.AccountNumber}"/>
            <apex:column 
              value="{!acctWrapper.cAccount.Name}"/>
         </apex:pageBlockTable>

         <!-- SELECTED ACCOUNT INFO -->
         <apex:pageBlockSection >
            <apex:outputPanel 
              layout="block" 
              rendered="{!hasSelAcct}">
               <apex:outputText 
                 value="Below are the selected account:"/>
               <br/>
               <apex:outputText 
                 value="{!selAccountNames}"/>
             </apex:outputPanel>
             <apex:outputPanel layout="block" 
               rendered="{!NOT(hasSelAcct)}">
                <br/>
                <apex:outputText value="No account selected."/>
             </apex:outputPanel>
         </apex:pageBlockSection>
      </apex:pageBlock>
   </apex:form>
</apex:page>

Note that we referenced our list variable while using the properties of our wrapper class in the controller .

28 March 2011

This will be the start of a good Salesforce Experience

Hello Guys! I've been in the consulting industry for 5 1/2 years and counting and started working as a .NET developer but later on switched to cloud development using Force.com technologies and now a certified developer and a future advance salesforce developer. I have been wanting to create a blog for quite sometime to share my experiences and tips, both nice and annoying during my career transition from OOP to cloud. This will not be a typical blog in which informations are copy and pasted from documentation as I want people to study on their own and uses this blog for workarounds and suggestions. From here on, I will try to update this blog and share my knowledge, some my real life use cases, designs and approaches I did to some of my projects.

Hope everybody, specially those that are new to the technology, benefits from this.