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:

26 comments:

  1. Thanks, excellent post. Saved me hours of head-scratching!

    John O'

    ReplyDelete
  2. Please tell me How to get which value is selected by user in picklist in visual force

    ReplyDelete
  3. Annu -

    The value the user selects is assigned to the variable in the 'value' attribute of the select list definition.

    In the above example, the value the user selects will be placed in the status field of the invoice statement object defined in the controller. You can access this in the controller by using invoiceStatement.Status__c

    ReplyDelete
  4. Christopher -- thanks for putting this together, just wanted to say I just used it and it works great.

    Ray
    http://raydehler.com/cloud/

    ReplyDelete
  5. hi
    i tried the same as follows but i am getting the following error could u plz help me



    Please select required status:







    Invalid identifier: MyContact__c it is the error

    ReplyDelete
    Replies
    1. Hello Suree,

      The error suggests that you may not be populating the select options incorrectly. Without seeing your code it is hard to know. If you post your code here or email it to me I can give you some pointers!

      Delete
    2. MyContact__c is the custom object and the Security_Question is the Picklist field on the MyContact__c object then how can i populate it from the object on to the visual force pages


      Please select required status:

      Delete
    3. Suree,

      This is how your code should look if you are using a custom object called MyContact and a field called Security Question

      VisualForce Page:

      <apex:page controller="NoNoneForPicklistController">

      Please select required security question:
      <apex:form >
      <apex:selectList size="1" value="{!myContact.Security_Question__c}">
      <apex:selectOptions value="{!securityOptions}"/>
      </apex:selectList>
      </apex:form>

      </apex:page>

      Controller:

      public class NoNoneForPicklistController{

      public MyContact__c myContact {get;set;}
      public List<SelectOption> securityOptions {get;set;}

      // Constructor called when page is accessed.
      public NoNoneForPicklistController() {

      myContact = new MyContact__c();
      securityOptions = new List<SelectOption>();

      // Use DescribeFieldResult object to retrieve status field.
      Schema.DescribeFieldResult securityFieldDescription = MyContact__c.Security_Question__c.getDescribe();

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

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

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


      hope that helps,

      Chris

      Delete
    4. i wrote the above code but it is giving the following error
      Error: Unknown property 'String.Security_Question__c'

      Delete
    5. Suree, my suggestion would be to first check that you have defined "myContact" as an object of type My_Contact__c in your controller. The above message seems to suggest you have defined it as a string.

      Delete
  6. Hi

    Suppose if there are two fields namely RequestedBy and Status in an Invoice Statement object.
    Picklist values of RequestedBy field are
    John
    Bob
    Ram

    Picklist values of Status field are
    Open
    Closed
    In Progress
    Cancelled.

    Can you please help me in getting these picklist values for the two fields in Visual force page. I tried but in one field only all the picklist values are showing(in one filed it is showing other field picklist values also).

    Regards,
    Jagadeesh

    ReplyDelete
    Replies
    1. Hi Jagadeesh,

      The following code should satisfy your requirements:

      *Page Code*

      <apex:page controller="NoNoneForPicklistController">

      <apex:form >

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

      <br/><br/>

      Who was this invoice requested by?:
      <apex:selectList size="1" value="{!invoiceStatement.Requested_By__c}">
      <apex:selectOptions value="{!requestedByOptions}"/>
      </apex:selectList>

      </apex:form>

      </apex:page>

      *Controller Code*

      public class NoNoneForPicklistController{

      public Invoice_Statement__c invoiceStatement {get;set;}
      public List<SelectOption> statusOptions {get;set;}
      public List<SelectOption> requestedByOptions {get;set;}

      public NoNoneForPicklistController() {

      invoiceStatement = new Invoice_Statement__c();
      statusOptions = new List<SelectOption>();
      requestedByOptions = new List<SelectOption>();

      Schema.DescribeFieldResult statusFieldDescription = Invoice_Statement__c.Status__c.getDescribe();

      for (Schema.Picklistentry picklistEntry: statusFieldDescription.getPicklistValues()){

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

      if (picklistEntry.defaultValue){
      invoiceStatement.Status__c = pickListEntry.getValue();
      }
      }

      Schema.DescribeFieldResult requestedByFieldDescription = Invoice_Statement__c.Requested_By__c.getDescribe();

      for (Schema.Picklistentry picklistEntry: requestedByFieldDescription.getPicklistValues()){

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

      if (picklistEntry.defaultValue){
      invoiceStatement.Requested_By__c = pickListEntry.getValue();
      }
      }
      }
      }

      I hope that helps. If you have any problems let me know.

      Cheers,

      Chris.

      P.S. Thanks for the questions, you have given me a great idea for my next post :D

      Delete
  7. Hi
    any body knows this scenario.when deptname has been selected in
    dropdown list ,then respective employees must be displayed in List.How can do this?

    ReplyDelete
    Replies
    1. This may work
      once you select a department from picklist, create another picklist with the list of employees and make it dependent to the department picklist

      Delete
    2. Hi KSR. I have created an example of what you are describing based on the Invoice Statement model in the post above. In the example, when a user selects a status value from a picklist, the invoice statements that have the selected status value are displayed in a table below.

      The code uses an action support Visualforce tag to automatically reload the list with the relevant objects when the picklist value is changed.

      Copy the following code, substituting your object/field names in, and let me know how you get on.

      Visualforce Page:

      <apex:page controller="NoNoneForPicklistController">

      <apex:form >

      <apex:pageblock >

      <apex:pageBlockButtons location="top">
      Please select required status:
      <apex:selectList size="1" value="{!selectedStatus}">
      <apex:selectOptions value="{!statusOptions}"/>
      <apex:actionSupport event="onchange" action="{!loadInvoiceStatements}"/>
      </apex:selectList>
      </apex:pageBlockButtons>

      <apex:pageBlockTable value="{!invoiceStatements}" var="inv">
      <apex:column value="{!inv.Name}"/>
      <apex:column value="{!inv.Invoice_Value__c}"/>
      <apex:column value="{!inv.Description__c}"/>
      <apex:column value="{!inv.Status__c}"/>
      </apex:pageBlockTable>

      </apex:pageblock>

      </apex:form>

      Controller Code:

      public class NoNoneForPicklistController
      {

      public String selectedStatus {get;set;}
      public List<SelectOption> statusOptions {get;set;}
      public List<Invoice_Statement__c> invoiceStatements {get;set;}

      public NoNoneForPicklistController()
      {

      statusOptions = new List<SelectOption>();

      Schema.DescribeFieldResult statusFieldDescription = Invoice_Statement__c.Status__c.getDescribe();

      for (Schema.Picklistentry picklistEntry: statusFieldDescription.getPicklistValues())
      {

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

      if (picklistEntry.defaultValue){
      selectedStatus = pickListEntry.getValue();
      }
      }

      loadInvoiceStatements();
      }

      public void loadInvoiceStatements()
      {
      invoiceStatements = [SELECT Name, Invoice_Value__c, Description__c, Status__c
      FROM Invoice_Statement__c
      WHERE Status__c = :selectedStatus];
      }
      }

      </apex:page>

      Delete
  8. Hi,
    Thanks for your cool post, helped me a lot, but one minor thing couldn't add with this, can you please help me to implement it.

    I have remove None value, but I want to show red line(required) on picklist field, but it is not showing by putting Required = true.

    ReplyDelete
    Replies
    1. Hi sem7114,

      I'm not sure how possible that is without applying some custom styling: see this thread here for more info

      http://boards.developerforce.com/t5/Visualforce-Development/required-attribute-not-working-correctly-on-apex-selectList/m-p/171987#M21771

      Regards,
      CAL

      Delete
  9. Hi Chris,

    I have a question can we show the recordtype name as picklist value using the schema.DescribeFieldResult.
    After looking at the schema.DescribeFieldResult methods I felt it is not possible. If i am wrong guide me please.

    Thanks.
    Suresh

    ReplyDelete
    Replies
    1. Hi Suresh,

      When entering the record type of an object using the Visualforce input field tag in a form, despite actually being a reference field, the record type appears on the page as a picklist. Even better, if the record type has an associated value for the object (is not blank) then the picklist will not appear with a "-none-" option.

      note: To include this picklist on a page, the tag is

      If for whatever reason you still want to get all of the possible values for the record type field, then this is possible using SOQL. It is not possible to get the values using describe field result, as the record type is a reference field rather than a picklist. Here is a great blog post on the subject, I hope it helps should you need it:

      http://www.salesforcefast.com/2009/06/look-up-record-type-ids-with-one-query.html

      Regards,
      CAL

      Delete
  10. Error: Samp Compile Error: unexpected token: 'bucketlevel__c' at line 2 column 7

    I had tried both methods as u posted:

    ReplyDelete
    Replies
    1. Hi Prasad

      Can you possibly post the code you have created, I may be able to point out any problems.

      Delete
  11. This comment has been removed by the author.

    ReplyDelete