Custom Multi-User Selection in Visualforce

​​

The idea behind our component is to store a map of the user Ids and the names of the user as you’d want to show the names of the users in the selection but would probably need the user Ids.

 

We prefer to base all of our Visualforce components on native Visualforce and Apex rather than Javascript. It’s then just easier to test our functionality without using automated UI tests such as Selenium tests. The disadvantage of using native Visualforce rather than Javascript is a bit slower feature since every button click the user will do would require a request to be sent to Salesforce.

<code class="rainbow" data-language="java">public class UsersSelectionController { public List<string> selectedUserIds { get; set; } public List<string> removedUserIds { get; set; } public String whereClause { get; set; } private Map<id, string=""> availableUsersMap; private Map<id, string=""> selectedUsersMap; public UsersSelectionController() { initializeCollections(); getUsers(); } private void initializeCollections() { selectedUserIds = new List<string>(); removedUserIds = new List<string>(); availableUsersMap = new Map<id, string="">(); selectedUsersMap = new Map<id, string="">(); } private void getUsers() { for (User u : [SELECT id, name FROM user WHERE IsActive = true]) { availableUsersMap.put(u.Id, u.Name); } } }</id,></id,></string></string></id,></id,></string></string></code>

 

We then add 2 methods to add and remove a user. When add is called, we’re looking at which users were selected in the available user's multi picklist. When remove is called, we’re looking for which users were selected in the selected user's multi picklist.

<code class="rainbow" data-language="java"><span class="keyword">public</span> <span class="keyword">void</span> <span class="entity function">add</span>() { <span class="keyword">if</span> (<span class="operator">!</span>selectedUserIds.<span class="entity function">isEmpty</span>()) { <span class="keyword">for</span> (<span class="entity class">String</span> userId <span class="operator">:</span> selectedUserIds) { selectedUsersMap.<span class="entity function">put</span>(userId, availableUsersMap.<span class="entity function">get</span>(userId)); availableUsersMap.<span class="entity function">remove</span>(userId); } } } <span class="keyword">public</span> <span class="keyword">void</span> <span class="entity function">remove</span>() { <span class="keyword">if</span> (<span class="operator">!</span>removedUserIds.<span class="entity function">isEmpty</span>()) { <span class="keyword">for</span> (<span class="entity class">String</span> userId <span class="operator">:</span> removedUserIds) { availableUsersMap.<span class="entity function">put</span>(userId, selectedUsersMap.<span class="entity function">get</span>(userId)); selectedUsersMap.<span class="entity function">remove</span>(userId); } } }</code>

 

Another important part is to add 2 getter methods that return a list of 'SelectOption' for each of the multi picklists.

<code class="rainbow" data-language="java"><span class="keyword">public</span> <span class="entity class">List</span><span class="operator"><</span><span class="entity class">SelectOption</span><span class="operator">></span> <span class="entity function">getAvailableUsers</span>() { <span class="entity class">List</span><span class="operator"><</span><span class="entity class">SelectOption</span><span class="operator">></span> availableUsers <span class="operator">=</span> <span class="keyword">new</span> <span class="entity function">List<selectoption></selectoption></span>(); <span class="keyword">for</span> (<span class="entity class">Id</span> userId <span class="operator">:</span> availableUsersMap.<span class="entity function">keySet</span>()) { availableUsers.<span class="entity function">add</span>(<span class="keyword">new</span> <span class="entity function">SelectOption</span>(userId, availableUsersMap.<span class="entity function">get</span>(userId))); } <span class="keyword">return</span> availableUsers; } <span class="keyword">public</span> <span class="entity class">List</span><span class="operator"><</span><span class="entity class">SelectOption</span><span class="operator">></span> <span class="entity function">getSelectedUsers</span>() { <span class="entity class">List</span><span class="operator"><</span><span class="entity class">SelectOption</span><span class="operator">></span> selectedUsers <span class="operator">=</span> <span class="keyword">new</span> <span class="entity function">List<selectoption></selectoption></span>(); <span class="keyword">for</span> (<span class="entity class">String</span> userId <span class="operator">:</span> selectedUsersMap.<span class="entity function">keySet</span>()) { selectedUsers.<span class="entity function">add</span>(<span class="keyword">new</span> <span class="entity function">SelectOption</span>(userId, selectedUsersMap.<span class="entity function">get</span>(userId))); } <span class="keyword">return</span> selectedUsers; }</code>

 

Last, we’ll add another filtering method which will allow the user to filter and search for a specific user within the available users's list.

<code class="rainbow" data-language="java"><span class="keyword">public</span> <span class="keyword">void</span> <span class="entity function">filterAvailableOptions</span>() { availableUsersMap <span class="operator">=</span> <span class="keyword">new</span> <span class="entity class">Map</span><span class="operator"><</span><span class="entity class">Id</span>, <span class="entity function">String></span>(); selectedUserIds <span class="operator">=</span> <span class="keyword">new</span> <span class="entity function">List<string></string></span>(); <span class="entity class">String</span> likeClause <span class="operator">=</span> <span class="char">'%'</span> <span class="operator">+</span> whereClause <span class="operator">+</span> <span class="char">'%'</span>; <span class="keyword">for</span> (<span class="entity class">User</span> u <span class="operator">:</span> [<span class="constant">SELECT</span> id, name <span class="constant">FROM</span> <span class="entity class">User</span> <span class="constant">WHERE</span> name like <span class="operator">:</span>likeClause]) { <span class="keyword">if</span> (<span class="operator">!</span>selectedUsersMap.<span class="entity function">containsKey</span>(u.<span class="entity class">Id</span>)) { availableUsersMap.<span class="entity function">put</span>(u.<span class="entity class">Id</span>, u.<span class="entity class">Name</span>); } } }</code>

 

The Visalforce would have 2 multi select lists, 2 buttons to add and remove and a search text input with a search button.

We used an HTML table to layout the table properly. You can then include this in any of your features and use the 'selectedUserIds' list to process the users that were selected.

<code class="rainbow" data-language="html"><span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:page <span class="support attribute">controller</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">UsersSelectionController</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:form <span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outPutLabel <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Search for: </span><span class="string quote">"</span><span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:inputText <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!whereClause}</span><span class="string quote">"</span> <span class="support attribute">style</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value"> margin: 10px;</span><span class="string quote">"</span><span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:commandButton <span class="support attribute">action</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!filterAvailableOptions}</span><span class="string quote">"</span> <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Find</span><span class="string quote">"</span> <span class="support attribute">rerender</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">availableUsersBlock</span><span class="string quote">"</span><span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">id</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">multiselectPanel</span><span class="string quote">"</span> <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">duelingListBox</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">table</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">layout</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">tbody</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">tr</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">td</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">selectCell</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">selectTitle</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputLabel <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Available Users</span><span class="string quote">"</span> <span class="support attribute">for</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">multiselectPanel:leftList</span><span class="string quote">"</span> <span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:selectList <span class="support attribute">id</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">availableUsersBlock</span><span class="string quote">"</span> <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!selectedUserIds}</span><span class="string quote">"</span> <span class="support attribute">multiselect</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">true</span><span class="string quote">"</span> <span class="support attribute">size</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">15</span><span class="string quote">"</span> <span class="support attribute">style</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">width: 200px;</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:selectOptions <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!availableUsers}</span><span class="string quote">"</span><span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:selectList<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">td</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">td</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">buttonCell</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">text</span><span class="string quote">"</span><span class="support tag close">></span>Add<span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">text</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:commandLink <span class="support attribute">action</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!add}</span><span class="string quote">"</span> <span class="support attribute">rerender</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">availableUsersBlock, selectedUsersBlock</span><span class="string quote">"</span> <span class="support attribute">id</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">btnRight</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:image <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">/s.gif</span><span class="string quote">"</span> <span class="support attribute">alt</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Add</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">rightArrowIcon</span><span class="string quote">"</span> <span class="support attribute">title</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Add</span><span class="string quote">"</span> <span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:commandLink<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">text</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:commandLink <span class="support attribute">action</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!remove}</span><span class="string quote">"</span> <span class="support attribute">rerender</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">availableUsersBlock, selectedUsersBlock</span><span class="string quote">"</span> <span class="support attribute">id</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">btnLeft</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:image <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">/s.gif</span><span class="string quote">"</span> <span class="support attribute">alt</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Remove</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">leftArrowIcon</span><span class="string quote">"</span> <span class="support attribute">title</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Remove</span><span class="string quote">"</span> <span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:commandLink<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">duelingText</span><span class="string quote">"</span><span class="support tag close">></span>Remove<span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">td</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">td</span></span> <span class="support attribute">class</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">selectCell</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputPanel <span class="support attribute">layout</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">block</span><span class="string quote">"</span> <span class="support attribute">styleClass</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">selectTitle</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:outputLabel <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">Selected Users</span><span class="string quote">"</span> <span class="support attribute">for</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">multiselectPanel:rightList</span><span class="string quote">"</span> <span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:selectList <span class="support attribute">id</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">selectedUsersBlock</span><span class="string quote">"</span> <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!removedUserIds}</span><span class="string quote">"</span> <span class="support attribute">multiselect</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">true</span><span class="string quote">"</span> <span class="support attribute">size</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">15</span><span class="string quote">"</span> <span class="support attribute">style</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">width: 200px;</span><span class="string quote">"</span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag-name">apex</span></span>:selectOptions <span class="support attribute">value</span><span class="support operator">=</span><span class="string quote">"</span><span class="string value">{!selectedUsers}</span><span class="string quote">"</span><span class="support tag close">/></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:selectList<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">td</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">tr</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">tbody</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">table</span></span><span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:outputPanel<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="support tag-name">apex</span></span>:form<span class="support tag close">></span> <span class="support tag"><span class="support tag"><</span><span class="support tag special">/</span><span class="su

 

Feel free to check out the full code with our unit tests in our Github.