Custom Picklist in Visualforce Page

Let's say that you're building a Visualforce page and you want to provide a picklist option for your users on the page. If the field where you want to store the selection is a picklist then you have no issue because the field definition will define that the page display a picklist when the Visualforce page is rendered. However, let's say that you want to display a picklist option based on a query from another object. How would you do that?

This is the exact issue I ran into last week and thought it would make a useful post. Basically, the use case for this would be a text field or relationship field as defined on the object under the Setup but providing your users a picklist with limited selections instead of a lookup option or text field.

In the sample I've written on this page I was simply trying to limit the number and type of records that a relationship field made available to the user. You probably know what I'm talking about if you ever created a custom relationship field on an object. When your user goes to use the lookup on the page, it opens a new window from which the user can search for records and then select one to populate back to the page. Anyway, I wanted to limit that functionality so that only specific records were permitted in the popup but still enforce the relationship integrity. Upon further investigation I found that it would probably be more simple for the user if I just provided a picklist instead of the lookup option on the page. This way I could truly control the records being populated into the picklist and enforce the relationship between records.

In this sample code I am going to make a Visualforce page to allow for editing of User records. However, I am going to create picklist options for the Manager field instead of letting the user user the standard lookup functionality. So let's get into the code.

First, we need to define our Visualforce page:

<apex:page standardController="User" extensions="userExtension" standardStylesheets="true">
<!--
	Created by: Greg Hacic
	Last Update: 7 April 2009 by Greg Hacic
	Questions?: greg@interactiveties.com
	Copyright (c) 2009 Interactive Ties LLC
-->
	<apex:sectionHeader title="User Edit" subtitle="{!User.Name}" help="/help/doc/user_ed.jsp?loc=help"></apex:sectionHeader>
	<apex:form>
		<apex:pageBlock title="User Edit" mode="edit">
			<apex:pageBlockButtons>
				<apex:commandButton action="{!save}" value=" Save "></apex:commandButton>
				<apex:commandButton action="{!cancel}" value="Cancel"></apex:commandButton>
			</apex:pageBlockButtons>
			<apex:pageBlockSection title="General Information" columns="2">
				<apex:inputField value="{!User.FirstName}"></apex:inputField>
				<apex:inputField value="{!User.UserRoleId}"></apex:inputField>
				<apex:inputField value="{!User.LastName}"></apex:inputField>
				<apex:inputField value="{!User.UserType}"></apex:inputField>
				<apex:inputField value="{!User.Alias}"></apex:inputField>
				<apex:inputField value="{!User.ProfileId}"></apex:inputField>
				<apex:inputField value="{!User.Username}"></apex:inputField>
				<apex:inputField value="{!User.IsActive}"></apex:inputField>
			</apex:pageBlockSection>
			<apex:pageBlockSection columns="1" showHeader="false">
				<apex:pageBlockSectionItem>
					<apex:outputLabel value="Manager" for="mgr"></apex:outputLabel>
					<apex:selectList id="mgr" value="{!User.ManagerId}" size="1" title="Manager">
						<apex:selectOptions value="{!mgrs}"></apex:selectOptions>
					</apex:selectList>
				</apex:pageBlockSectionItem>
			</apex:pageBlockSection>
		</apex:pageBlock>
	</apex:form>
</apex:page>

What you'll notice in the code above is that the page is pretty simple. I've defined a section in the page containing a bunch of standard inputFields and the page will use the field definitions to display the appropriate input fields for them. For Example, the {!User.IsActive} reference will enforce that this input is a checkbox and the {!User.FirstName} reference will enforce that this input is a text field. The piece of the code that is relevant to this particular post is the stand-alone <apex:pageBlockSection> containing the <apex:pageBlockSectionItem> tag. This is the portion of my code where I will essentially dictate to the page that I want to use a picklist for the {!User.ManagerId} reference instead of the standard lookup functionality.

I also want to point out that I've defined that the page will use the standard controller for User and it will also use an extension class "userExtension". This custom extension is what we'll write next.

/*
	Created by: Greg Hacic
	Last Update: 7 April 2009 by Greg Hacic
	Questions?: greg@interactiveties.com
	Copyright (c) 2009 Interactive Ties LLC
*/
public class userExtension {
	private final User u; //User sobject
	
	//initializes the private member variable u by using the getRecord method from the standard controller
	public userExtension(ApexPages.StandardController stdController) {
		this.u = (User)stdController.getRecord();
	}
	
	//builds a picklist of user names based on their profile
	public List<selectOption> getMgrs() {
		List<selectOption> options = new List<selectOption>(); //new list for holding all of the picklist options
		options.add(new selectOption('', '- None -')); //add the first option of '- None -' in case the user doesn't want to select a value or in case no values are returned from query below
		for (User users : [SELECT Id, Name FROM User WHERE Profile.Name = 'System Administrator']) { //query for User records with System Admin profile
			options.add(new selectOption(users.Id, users.Name)); //for all records found - add them to the picklist options
		}
		return options; //return the picklist options
	}
}

As you can see the extension is also relatively simple. The important part here is the getMgrs method, which defines the picklist for use by the Visualforce page.

In order to finalize this code and make it deployable we will need a test class. That code is below:

/*
	Created by: Greg Hacic
	Last Update: 7 April 2009 by Greg Hacic
	Questions?: greg@interactiveties.com
	Copyright (c) 2009 Interactive Ties LLC
*/
public class userEditTEST {
	public static testMethod void testUserEdit() {
		//get a user that is not in a system admin profile
		User u = [SELECT Id, Name FROM User WHERE Profile.Name != 'System Administrator' LIMIT 1];
		
		//create a reference to the Visualforce page
		PageReference editPage = Page.userEdit;
		Test.setCurrentPage(editPage);
				
		//populate the Visualforce page with the Id of the user from above
		ApexPages.currentPage().getParameters().put('id', u.Id);
		
		//create an instance of the controller extension as if editing the user's details
		ApexPages.StandardController sc = new ApexPages.standardController(u);
		userExtension ext = new userExtension(sc);
		
		//call the method for populuating the picklist
		List<selectOption> managerList = ext.getMgrs();
		sc.save();
	}
}

I built this example to illustrate something that I think may be useful to most Visualforce developers. As I mentioned in the beginning of my post I was unable to find an example like this on the web. So hopefully this sample code helps to fill that void.

Automated Exchange Rates in Salesforce.com

Reduce Repetitive Tasks, Eliminate Errors & Free Up Your Administrators.

Birthday Reminders for Salesforce.com

It might lead to a sale. Or it might make you feel good.