Working With Multiselect Picklists

Working with Picklists essentially is rewarded since it limits the options of the user and standards what is valid as a value for a field in the system. As good as they are however they bring their own complexity with them.

This is especially true when you are working with multi-select Picklists. Mostly Visualforce’s inputField is used to view multi-select Picklists as Salesforce team is working on it to be more effective and error-free.

In this article we will see how to use the multi-select Picklists.

First off, let’s see how we can load values into our Picklist and view it on our Visualforce page.
Let’s say I have a custom multi-select Picklist field on my User object to define sales regions my users operate on.

The picklist has values such as:
  • North America
  • Latin America
  • Europe
  • Asia
  • Middle East
  • Africa
and so on

In my controller class I add the following property:




public class multiselectPicklist {
private User salesRegions;

public multiselectPicklist()
{
salesRegions = new User();
}
public User getSalesRegions() {
return salesRegions;
}
public void setSalesRegions(User Value) {
salesRegions = Value;
}
}




As you can see it is enough to create a new User object and later on use the picklist field to show the values on your page. Unfortunately there is no other way through which you would more control over what values are shown on your multi-select control. May be in future Salesforce will supply a Component for multi-select operations.

Please note that I have created a setter property as well that receives a User object. This setter allows us to later on read the selected values by user.

Now that we have our controller ready we can program our page to view our multi-select picklist.
in this example what I am trying to achieve is that to allow the user choose as many regions as he/she wants and them filter the Users of the system and view only those who are assigned to those regions.




<apex:page controller="multiselectPicklist" tabStyle="User" sideBar="false">
<apex:form >
<apex:sectionHeader title="Users by Region Report"></apex:sectionHeader>

<apex:pageBlock id="pageBlock" title="Search Filter">
<apex:pageMessages ></apex:pageMessages>
<apex:pageBlockSection title="Filters" columns="2" collapsible="true">
<apex:inputField id="salesRegions" value="{!salesRegions.Sales_Regions__c}" ></apex:inputField>
</apex:pageBlockSection>
</apex:pageBlock>
<apex:pageBlock id="searchResults" title="Results">
<apex:pageBlockButtons >
<apex:commandButton value="Run Report" action="{!runReport}" status="status" rerender="searchResults"></apex:commandButton>
</apex:pageBlockButtons>
<apex:pageMessages ></apex:pageMessages>
<apex:pageBlockTable value="{!users}" var="u" rendered="{!NOT(ISNULL(users))}" rules="cols">
<apex:column value="{!u.UserName}"></apex:column>
<apex:column value="{!u.IsActive}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:Page>




Something that you should bear in mind is that even though multi-select option suggests that you should be dealing with a list of Strings as a result of user’s interaction with your control on the page all you will receive will just a semicolon separated string. It is your job to separate the values and use then in whatever endeavor you intend to have.



Below on my button action I have demonstrated how you can read the selected values back and use them in your query to get a list of users in those sales regions:





public PageReference runReport() {

if (salesRegions.Sales_Regions__c == null || salesRegions.Sales_Regions__c == '') {
apexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO, 'Please select one or more regions first.'));
return null;
}
// read the values into an array
string[] regions = salesRegions.Sales_Regions__c.split(';',0);
if (regions != null && regions.size() > 0)
{
//query the database based on the user's selection
users = [select Username, IsActive, Id from user where Sales_Regions__c in :regions and IsActive = true order by Username];
}

return null;
}

private List<User> users;

public List<User> getUsers()
{
return users;
}
}





Something funny that occurred to me was that I tried to hook the Multi-select Component (inputField) with actionSupport to capture onChange event and load values of another Picklist item on my project which was totally a disappointment! It seems that the Salesforce team has been able to get that one to work yet.

12 comments:

  1. Thanks for the post; very nice! We are having an issue with Visualforce pages due to that fact that inputFields do not respect recordtpes. So when we try to duplicate an existing pagelayout with a slight tweak, the picklists on the page contain ALL of the value and not the values for that recordtype. A fix is on the roadmap but SFDC does not know when. Is there are way to query by recordtype to get the picklist values and build your own picklist?

    ReplyDelete
  2. Referring to this post:
    PickList Component
    I may have answered your question.
    I have not yet developed a Component for multi-select Picklists though and that is yet a challenge when we are working with inputField. But I hope this soon will be rectified.

    ReplyDelete
  3. Good article, but proofread your English a bit more. There are some run-on sentences, accidently missing words (like in the last paragraph), etc.

    ReplyDelete
  4. This is an excellent example. However, query seems to get no results...Issue seems to be with the "where Sales_Regions__c in :regions..." part of where clause...I can't see what is wrong with it...I am running with 19.0 API.

    ReplyDelete
  5. @Sam Arjmandi, hello sam, i want to do certification of developer in salesforce.so will you please give me some tutorial or material so that i can prepare for it.

    ReplyDelete
  6. Hello Sam,

    I would like to use list of account names (standard object) for the purposes of multi-select, so that I can selectively assign specific accounts to a custom Object called "Promotion"

    Can you please let me know if its possible? and how to go about it?

    ReplyDelete
  7. I am not sure what you are trying to do.
    How would you be able to link several account records to one custom object?

    ReplyDelete
  8. Hello Sam..In the relational DB sense, what I am indicating is the 1:N values... One PROMOTION (PROMO-100) can be given to ONLY select FEW ACCOUNTS (Customers..e.g. ABC Company, DEF Corp, PQR LLC.) In that case..When I am in PROMITIONS Object (Layout) on the screen, I would like to associate that promotion with multiple accounts by providing a multi-select value list which consists of all the customers..but our admin will chose to pick 3 or 4 Customer accounts that qualify for that promotion. Hope that explains. Thanks for your time.

    ReplyDelete
  9. Hi, i would like to know if there's a way to get the values or a PickList MultiSelect that have never been selected?
    Is this capable without using a query for all the Items to see if they exist

    ReplyDelete
  10. Hi Sam
    Is it possible that I can add all the product names from Product Object in a multiselect picklist custom field called Building or whatever in a Case object. So that when I am creating a new Case record, I am able to select multiple buildings as well and associate them with that case.

    ReplyDelete
  11. how do i create reports for separate values of multiselect picklist value

    ReplyDelete
  12. Hello Sam,

    I want to display page blocks depending upon the selection of value from multi select pickslist. So what is the way to achieve it?

    Please help!

    Thanks,
    Gayatri.

    ReplyDelete