Monday, 4 October 2010

Creating a picklist in a Visualforce page without a -none- value

Update (7th August 2012): I have developed a new Visualforce component version of this functionality, for those who want to re-use this feature numerous times.

When building a custom Visualforce page, the need may arise to include a combo-box input based on a picklist field inside a Salesforce object. This is easy to achieve using an apex:inputField, as in the following example, where an Invoice Statement object contains a picklist field called Status.

VisualForce Page:
<apex:page controller="NoNoneForPicklistController">

    Please select required status:
    <apex:form >
        <apex:inputField value="{!invoiceStatement.Status__c}"/>
    </apex:form>  

</apex:page>
Controller:
public class NoNoneForPicklistController{

    public Invoice_Statement__c invoiceStatement {get;set;}
    
}

Screen-shot:


As you can see, the default value on the combo-box on the page is "-None-", which represents an empty value. It may be a preference to not display the empty value, but rather frustratingly, no configuration of the picklist object field can avoid this inclusion. There is no way to mark a picklist field as "required", and setting an option as default makes no difference either. That said, there are already ways to prevent an empty value being processed, using validation and feedback, but I have always been one to believe that prevention is better than cure.

Thankfully, there is a way to effectively create a picklist on a Visualforce list with no empty value. This can be achieved by using the Schema.DescribeFieldResult Salesforce standard class to retrieve all the possible field label value pairs for a picklist field. The retrieved value pairs are then stored inside a collection of select option objects, which can be used as the basis of a select list. Below is a snapshot of the code from the apex controller, and also the Visualforce page. As an added bonus, the default value specified in the picklist field object configuration can be used to set the initially selected value of the select list.

VisualForce Page:
<apex:page controller="NoNoneForPicklistController">

    Please select required status:
    <apex:form >
        <apex:selectList size="1" value="{!invoiceStatement.Status__c}">
            <apex:selectOptions value="{!statusOptions}"/>
        </apex:selectList>
    </apex:form>  

</apex:page>

Controller:
public class NoNoneForPicklistController{

    public Invoice_Statement__c invoiceStatement {get;set;}
    public List<SelectOption> statusOptions {get;set;}
    
    // Constructor called when page is accessed.
    public NoNoneForPicklistController() {
    
        invoiceStatement = new Invoice_Statement__c();        
        statusOptions = new List<SelectOption>();

        // Use DescribeFieldResult object to retrieve status field.
        Schema.DescribeFieldResult statusFieldDescription =                     Invoice_Statement__c.Status__c.getDescribe();

        // For each picklist value, create a new select option
        for (Schema.Picklistentry picklistEntry:                                statusFieldDescription.getPicklistValues()){

            statusOptions.add(new SelectOption(                                     pickListEntry.getValue(),pickListEntry.getLabel()));

            // obtain and assign default value
            if (picklistEntry.defaultValue){
                invoiceStatement.Status__c = pickListEntry.getValue();
            }  
        }     
    }
}

Screen-shot:

Friday, 24 September 2010

Converting decimal value to integer (don't fall into the trap!!)

During data handling within an application, it is not unusual to have a requirement to convert a decimal value into an integer equivalent. When attempting to do accomplish this inside Apex code, you may think that writing something similar to the following will perform the conversion:

Decimal decimalValue = 12.0;
Integer integerValue = Integer.valueOf(decimalValue);

Using code like this will compile without a problem, but upon execution, an error message "System.TypeException: Invalid Integer" will appear (see screen-shot for an example). This is because the input variable "decimalValue" contains more than just numbers, it also contains a decimal place, which causes the conversion to be rejected by the "valueOf" function.


The method that should always be used to perform this kind of conversion is *decimal variable*.intValue(). So in our example above the Apex code should look like this:

Decimal decimalValue = 12.0;
Integer integerValue = decimalValue.intValue();


Now the conversion will work without error.

Wednesday, 18 August 2010

Displaying different date formats on Visualforce pages.

A common requirement of a Salesforce application is to display date and time information. What is not so common, is how this information needs to be displayed.

Varying the format of a dateTime field inside a Visualforce page is quite straightforward. It involves wrapping the field in a mask and then passing the data as a parameter, like so:

Page:
<apex:outputText value="{0,date,{!dateFormat}}">
     <apex:param value="{!myDateTime}" />
</apex:outputText>

In order to illustrate how this works, I have constructed a page and controller with a few samples. Below is a screenshot of the page displaying a single date (31st December 2010, 23:59:59) in various different formats. The first column of the table shows the string used as the date format mask, whilst the second column shows how that date appears when the mask is applied to the date.


Note that for formats that include literal text, escape characters are required in the controller so that the result renders properly. In my example, Day of the year has to be written as \'Day of the year\' in the formatting String. For all those interested, here is the page and controller code I used to construct the page:

Controller:
public class DateFormattingController {

  Datetime myDateTime = datetime.newInstance(2010, 12, 31, 23, 59, 59);

  List<String> dateFormats = new List<String> {
     'dd.MM.yy HH:mm:ss',
     'MMM-dd-yyyy hh:mm a',
     'EEEEE dd MMMMM yyyy G',
     'E hh:mm:ss:SSS z',
     'zzzzz (Z), \'Day of the year:\' D' 
  };
   
  public DateTime getMyDateTime(){
    return myDateTime;
  }

  public List<String> getDateFormats(){
    return dateFormats;
  }
}

Page:
<apex:page controller="DateFormattingController">
    
    <apex:sectionHeader title="Date Formatting"/>
    
    <apex:outputText value="Standard Output Format: {!myDateTime}"/>
    
    <apex:pageBlock >
        <apex:pageBlockTable value="{!dateFormats}" var="dateFormat">
            <apex:column headerValue="Date Format" value="{!dateFormat}"                                   width="50%"/>
            <apex:column headerValue="Output" width="50%">
                <apex:outputText value="{0,date,{!dateFormat}}">
                    <apex:param value="{!myDateTime}" />
                </apex:outputText>
            </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>
    
</apex:page>

See Paul's Salesforce Blog for the full date format letter table. Any missing formats or unsure how to construct a particular format, leave me a comment on the post and I'll see what I can do!

Friday, 30 July 2010

"Check All" checkbox in an apex:dataTable (without using scripts)

Recently, a business requirement emerged for a client whereby a user needed to be able to select a number of contacts from a data table, and then carry out some business logic on those selected clients. The process of selecting several contacts using a wrapper class is easy enough, but what about a simple way to select and deselect all of the records in one go? This can be achieved placing a checkbox in the header element of the column. I found an example solution that uses a javascript function embedded on the page to copy the true/false value of the header checkbox to all the boxes in the column.

This certainly does the job, but I found from a design perspective it had some limitations. The javascript function it calls gets the elements by tag, specifically the input tag, which may be used elsewhere if the page you are designing contains more than just this data table. Also, placing selection controls in scripts divides the selection logic between two entities; the page and the apex controller class.

With this in mind, I started to think about how I could develop an equivalent solution that uses logic inside the controller to change the state of all of the checkboxes. This is the solution I came up with:

Controller:
public class CheckboxCheckAllController {
 
 public List<ContactWrapper> allContacts { get; set; }
 public Boolean allChecked { get; set; }
 
 public CheckboxCheckAllController () {
  allContacts = new List<ContactWrapper>();
  allChecked = false;
  
  for(Contact contact: [select Name, Title, Department, Email from Contact ]){ 
   allContacts.add(new ContactWrapper(contact));
  } 
 }
 
 public PageReference CheckAll(){
  
  for(ContactWrapper contact : allContacts){
   contact.selected = allChecked;
  }
  
  return null;
 }
 
 public PageReference ProcessSelectedContacts(){
  
  for (ContactWrapper contactWrapper : allContacts ){
   if(contactWrapper.selected == true){
    /* Do Some Processing */
   }
  }
  
  return null;
 }

 public class ContactWrapper {
  
  public Contact con{get; set;}
        public Boolean selected {get; set;}
        
        public ContactWrapper(Contact c){
            con = c;
            selected = false;
        }
        
 }
}

Page:
<apex:page controller="CheckboxCheckAllController">

  <apex:form>

    <apex:dataTable value="{!allContacts}" var="c" id="contactsTable">
      <apex:column>
        <apex:facet name="header">
          <apex:inputCheckbox value="{!allChecked}">
            <apex:actionSupport event="onclick" action="{!CheckAll}"
                                rerender="contactsTable"/>
          </apex:inputCheckbox>
        </apex:facet>
        <apex:inputCheckbox value="{!c.selected}"/>
      </apex:column>
      <apex:column value="{!c.con.Name}" headervalue="Full Name"/>
      <apex:column value="{!c.con.Title}" headervalue="Title"/>
      <apex:column value="{!c.con.Department}" 
                   headervalue="Department"/>
      <apex:column value="{!c.con.Email}" headervalue="Email"/>
    </apex:dataTable>

    <apex:commandButton action="{!ProcessSelectedContacts}" 
                        value="Process Selected Contacts"/>

  </apex:form>
</apex:page>

Page In Browser:


Admittedly, it provides a slightly slower response time than the pure javascript, but I think this provides benefits in singularity of location of control code and adaptability, as you can control the behaviour of the selection using array logic.

Thursday, 22 July 2010

Report Builder Developer Preview Webinar Feedback

Today I took part in the new Report Builder Webinar, which included a demonstration of the new builder tool Salesforce has created in response to users commenting that the existing wizard was clumsy and made making changes a very arduous process. In the past, creating a single report involved plodding through seven setup screens, which all have to be repeated if you want to make a single change, and there is no clue as to what the report will look like until all these preparation steps have been completed. The new tool is much more interactive, providing a single screen with an active preview of the report based on a small portion of your existing data. The report is refreshed every time you make a change, so you always have an exact idea of the reports end appearance.

The Report Builder is already available in all developer editions. To really appreciate the improvement, I had a go at creating a few simple reports using both the standard wizard and the new report builder. Using the new tool is a vast improvement and a lot more intuitive. I was able to add fields, change the order of fields, order data, group rows and impose date period restrictions on fields immediately using built in menus. The report builder can create reports for both standard and custom objects, and even pre-prepares standard report templates for custom objects based on their relationships with other Salesforce objects.

To access the report builder, click on the Reports tab (can be included in an app through setup if not there already), and then on the “Create Report With Report Builder” button. The “Create New Custom Report” button allows you to use the old report wizard.

The report builder will be rolled out to all editions in the Winter ’11 release later this year, so is not immediately available to create and manipulate reports in Salesforce applications. However, because the underlying metadata for reports is the same no matter which composer is used, you could potentially use developer accounts to create the reports using the new builder and then copy the metadata to your production application. For this to work you must ensure that the underlying object models between the developer copy and your production org are the same.

Tuesday, 20 July 2010

Frustrations with the home page default view for objects

Throughout my time using the Force platform, I have found the default view displayed on object home pages clumsy and counter intuitive. Here is an example of a home page for a custom object, merchandise, that featured as part of the exercises inside the Force.com workbook.


Now, imagine you are looking at this view for the first time, you see a list of Merchandise objects (Wee Speedboat, Wee Train, Wee Jet) and the view indicator says 'All', this must be all of the Merchandise records in the system right? Wrong!! this is actually a list of merchandise records that were recently viewed by you. This is indicated by a small drop down box on the right hand side of the screen, where you don't instinctively think to look. Worse still, the two other options in the list 'Recently Created' and 'Recently Modified' only show the records that you personally have created or modified, so from an overall data perspective, you have no idea what is going on.

While these views are useful in certain approaches and data models, I do not understand why they are part of a default view that cannot be changed. If you open the 'All' view by clicking on the 'Go!' button, you get the following view on the screen.


I feel that even this would be a more suitable home page, with 'Recently Modified', 'Recently Viewed' and 'Recently Created' all as standard views on the drop down menu (with the words 'by you' after them for clarity). If a report page block was required as is necessary with some objects, this could be included underneath the view section.

The issue has been raised in the Salesforce idea exchange but no solution has been introduced in the four years since this was posted, which I find frankly unbelievable. Salesforce's view on this issue seems to be that if customizations to the default view are required, then a Visualforce page can be created with the appropriate appearance. Still, I don't see why the appearance can't be changed in the same way that objects have an individual record page layout that can be customised. It could be as simple as allowing the user to decide if they want the recent list and the default view that they wish to use.

With this in mind, I am seriously considering trying my hand at developing an application for the Salesforce AppExchange which would provide a simple menu that administrators could click through to create a basic custom home page for a particular object, views included.

Thursday, 1 July 2010

Adding alphabetical lists in Salesforce PDFs

One of the better features of Salesforce and apex programming is the ability to generate Visualforce pages as PDFs by simply using the renderAs="pdf" attribute notation in the apex:page tag. However, recently when using this feature to generate a list of conditions, I noticed that whenever you define an apex datalist, or an ordered list in html that uses letters (a,b,c,d) as the markers for each element in the list, these are rendered in the PDF incorrectly.

Take the following example of a page and controller:

Page:
<apex:page showHeader="false" controller="LetterListController" standardStylesheets="false" sidebar="false">

<apex:dataList value="{!accounts}" type="a" var="account" id="theList" >
<apex:outputText value="{!account.name}"/>
</apex:dataList>

<ol type="a">
<li>First Item</li>
<li>Second Item</li>
<li>Third Item</li>
<li>Last Item</li>
</ol>

</apex:page>

Controller:
public class LetterListController {

List<Account> accounts;

public List<Account> getAccounts() {
if(accounts == null) accounts = [select name from account limit 10];
return accounts;
}
}


When the Letter List page is rendered in Salesforce, the following output appears-


Absolutely fine, but when we add the renderAs="pdf" attribute in the page tag definition, the PDF output is -


The apex datalist has been rendered as a list with blobs, while the html list has been changed to be ordered by numbers. This is quite frustrating, but the solution is simple. You can choose the bullet point class of a list using the css attribute list-style-type. So all we need to do is create a style class on the page inside head tags, and then apply this class to the two lists.

Page:

<apex:page showHeader="false" controller="LetterListController" standardStylesheets="false" sidebar="false" renderas="PDF">

<head>
<style>
.letterList{
list-style-type: lower-alpha;
}
</style>
</head>


<apex:dataList value="{!accounts}" var="account" id="theList" styleClass="letterList">
<apex:outputText value="{!account.name}"/>
</apex:dataList>

<ol class="letterList" type="a">
<li>First Item</li>
<li>Second Item</li>
<li>Third Item</li>
<li>Last Item</li>
</ol>

</apex:page>

The output PDF is now -


Tuesday, 29 June 2010

"Chatter-Bot" scoops grand prize in Chatter Developer Challenge

The Salesforce Chatter Developer challenge has ended and the winner has been announced as Chatter Bot by Michael Leach. Chatter Bot is a project that enables the transfer of real world physical sensor data to the Salesforce cloud in the form of Chatter.The Chatter Bot has it's very own personal profile within Chatter, and updates subscribers of significant readings from light and motion sensors.

The following video shows Chatter Bot in action


What impresses me most about this idea is that it really plays on Chatters aim of making information more personable and efficient. Using sensors in this context may get scientists and security organisations thinking about how they could make effective use of combining sensor input with cloud technology.

A Chatter adaptation for the Android mobile phone platform developed by Jeff Douglas came second in the competition. Third place was shared by three separate projects; Location Glimpse; a location sharing application, Txt2Chatter; a text message service that allows users to remotely update their status, and Feed Sentiment; providing managers with an overview of how the sales team is feeling about current opportunities.

Wednesday, 9 June 2010

2 uses of the apex:outputPanel tag

Throughout my experience with the force, I have come across a few problems where the solution involved simply the inclusion an apex:outputPanel tag. Below are two uses that are not commonly known.

  1. Multi-component facets

    When using facets, salesforce only allows for a single sub-component as the contents. If you require multiple components, such as an image and text for an action status, then simply enter an apex:outputPanel tag inside the facet, then place all of your components inside.


  2. Partial form refreshing

    When developing apex pages, a common request is to make components appear and hide using the 'rendered' attribute. If a component is hidden, and an action occurs that then requires that component to be shown, you cannot simply re-render the component, as it was never rendered and so does not exist in the current context of the page. Normally this means you have to refresh an entire form, but this can be avoiding using an ouput panel around the components to be shown and hidden, and by using the id of the output panel in the 'reRender' attribute of the action



Wednesday, 26 May 2010

An Introduction

I am currently working on creating a prototype system on the Force.com cloud computing development platform. Using cloud based technology has allowed the client I worked for to access and interact with their data directly and securely from anywhere using an internet browser, whilst improving the user experience significantly with an interactive graphical user interface over a standard "green screen" approach.

While working with this technology, I have found that the best insight and practical advice on using the platform actually comes from personal blogs. With this in mind, the purpose of this blog is to publish my own hints, tips and experiences using the Force.com platform and also report on and provide links to the latest emerging cloud computing technology.

Please bookmark this blog and keep in touch. Enjoy!

As a final note, I would like to thank Jason Venable and Jeff Douglas for their blogs, which have provided helpful solutions and techniques to employ while using the force.