Visualforce Component
=====================
<!--
The MultiselectPicklist component implements a multiselect picklist similar
to that seen when adding tabs to a Force.com application.
HTML elements use the same classes as the native multiselect picklist, to
keep visual consistency in the UI.
In addition to the visible elements, the component contains two hidden input
elements, the purpose of which is to hold a string representation of the
contents of each listbox. As options are added, removed or moved within the
listboxes, the content of the hidden elements is synchronized to the content
of the listboxes. When the Visualforce page is submitted, the
MultiselectController updates its SelectOption[] variables from these hidden
elements.
-->
<apex:component controller="MultiselectController">
<apex:attribute name="leftLabel" description="Label on left listbox."
type="String" required="true" />
<apex:attribute name="rightLabel" description="Label on right listbox."
type="String" required="true" />
<apex:attribute name="size" description="Size of listboxes."
type="Integer" required="true" />
<apex:attribute name="width" description="Width of listboxes."
type="String" required="true" />
<apex:attribute name="leftOptions"
description="Options list for left listbox." type="SelectOption[]"
required="true" assignTo="{!leftOptions}" />
<apex:attribute name="rightOptions"
description="Options list for right listbox." type="SelectOption[]"
required="true" assignTo="{!rightOptions}" />
<apex:outputPanel id="multiselectPanel" layout="block" styleClass="duelingListBox">
<table class="layout">
<tbody>
<tr>
<td class="selectCell">
<apex:outputPanel layout="block" styleClass="selectTitle">
<!--
Visualforce prepends the correct prefix to the outputLabel's
'for' attribute
-->
<apex:outputLabel value="{!leftLabel}"
for="multiselectPanel:leftList" />
</apex:outputPanel>
<select id="{!$Component.multiselectPanel}:leftList"
class="multilist" multiple="multiple" size="{!size}"
style="width: {!width};">
<apex:repeat value="{!leftOptions}" var="option">
<option value="{!option.value}">{!option.label}</option>
</apex:repeat>
</select>
</td>
<td class="buttonCell">
<apex:outputPanel layout="block" styleClass="text">Add</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="text">
<apex:outputLink value="javascript:moveSelectedOptions('{!$Component.multiselectPanel}:leftList',
'{!$Component.multiselectPanel}:rightList', '{!$Component.leftHidden}',
'{!$Component.rightHidden}');"
id="btnRight">
<apex:image value="/s.gif" alt="Add" styleClass="rightArrowIcon"
title="Add" />
</apex:outputLink>
</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="text">
<apex:outputLink value="javascript:moveSelectedOptions('{!$Component.multiselectPanel}:rightList',
'{!$Component.multiselectPanel}:leftList', '{!$Component.rightHidden}',
'{!$Component.leftHidden}');"
id="btnLeft">
<apex:image value="/s.gif" alt="Remove"
styleClass="leftArrowIcon" title="Remove" />
</apex:outputLink>
</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="duelingText">Remove</apex:outputPanel>
</td>
<td class="selectCell">
<apex:outputPanel layout="block" styleClass="selectTitle">
<apex:outputLabel value="{!rightLabel}" for="multiselectPanel:rightList" />
</apex:outputPanel>
<select id="{!$Component.multiselectPanel}:rightList"
class="multilist" multiple="multiple" size="{!size}"
style="width: {!width};">
<apex:repeat value="{!rightOptions}" var="option">
<option value="{!option.value}">{!option.label}</option>
</apex:repeat>
</select>
</td>
<td class="buttonCell"><apex:outputPanel layout="block"
styleClass="text">Up</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="text">
<apex:outputLink value="javascript:slideSelectedOptionsUp('{!$Component.multiselectPanel}:rightList',
'{!$Component.rightHidden}');"
id="upBtn">
<apex:image value="/s.gif" alt="Up" styleClass="upArrowIcon"
title="Up" />
</apex:outputLink>
</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="text">
<apex:outputLink value="javascript:slideSelectedOptionsDown('{!$Component.multiselectPanel}:rightList',
'{!$Component.rightHidden}');"
id="downBtn">
<apex:image value="/s.gif" alt="Down" styleClass="downArrowIcon"
title="Down" />
</apex:outputLink>
</apex:outputPanel>
<apex:outputPanel layout="block" styleClass="text">Down</apex:outputPanel>
</td>
</tr>
</tbody>
</table>
<apex:inputHidden value="{!leftOptionsHidden}" id="leftHidden" />
<apex:inputHidden value="{!rightOptionsHidden}" id="rightHidden" />
</apex:outputPanel>
<script type="text/javascript">
if (!buildOutputString) {
// Create a string from the content of a listbox
var buildOutputString = function(listBox, hiddenInput) {
var str = '';
for ( var x = 0; x < listBox.options.length; x++) {
str += encodeURIComponent(listBox.options[x].value) + '&'
+ encodeURIComponent(listBox.options[x].text) + '&';
}
str.length--;
hiddenInput.value = str.slice(0, -1);
}
}
if (!moveSelectedOptions) {
// Move the selected options in the idFrom listbox to the idTo
// listbox, updating the corresponding strings in idHdnFrom and
// idHdnTo
var moveSelectedOptions = function(idFrom, idTo, idHdnFrom, idHdnTo) {
listFrom = document.getElementById(idFrom);
listTo = document.getElementById(idTo);
for ( var x = 0; x < listTo.options.length; x++) {
listTo.options[x].selected = false;
}
for ( var x = 0; x < listFrom.options.length; x++) {
if (listFrom.options[x].selected == true) {
listTo.appendChild(listFrom.options[x]);
x--;
}
}
listTo.focus();
buildOutputString(listFrom, document.getElementById(idHdnFrom));
buildOutputString(listTo, document.getElementById(idHdnTo));
}
}
if (!slideSelectedOptionsUp) {
// Slide the selected options in the idList listbox up by one position,
// updating the corresponding string in idHidden
var slideSelectedOptionsUp = function(idList, idHidden) {
listBox = document.getElementById(idList);
var len = listBox.options.length;
if (len > 0 && listBox.options[0].selected == true) {
return;
}
for ( var x = 1; x < len; x++) {
if (listBox.options[x].selected == true) {
listBox.insertBefore(listBox.options[x],
listBox.options[x - 1]);
}
}
listBox.focus();
buildOutputString(listBox, document.getElementById(idHidden));
}
}
if (!slideSelectedOptionsDown) {
// Slide the selected options in the idList listbox down by one position,
// updating the corresponding string in idHidden
var slideSelectedOptionsDown = function(idList, idHidden) {
listBox = document.getElementById(idList);
var len = listBox.options.length;
if (len > 0 && listBox.options[len - 1].selected == true) {
return;
}
for ( var x = listBox.options.length - 2; x >= 0; x--) {
if (listBox.options[x].selected == true) {
listBox.insertBefore(listBox.options[x + 1],
listBox.options[x]);
}
}
listBox.focus();
buildOutputString(listBox, document.getElementById(idHidden));
}
}
// initialize the string representations
buildOutputString(document.getElementById('{!$Component.multiselectPanel}:leftList'),
document.getElementById('{!$Component.leftHidden}'));
buildOutputString(document.getElementById('{!$Component.multiselectPanel}:rightList'),
document.getElementById('{!$Component.rightHidden}'));
</script>
</apex:component>
Controller for above component:
================================
/*
* MultiselectController synchronizes the values of the hidden elements to the
* SelectOption lists.
*/
public with sharing class MultiselectController {
// SelectOption lists for public consumption
public SelectOption[] leftOptions { get; set; }
public SelectOption[] rightOptions { get; set; }
// Parse &-separated values and labels from value and
// put them in option
private void setOptions(SelectOption[] options, String value) {
options.clear();
String[] parts = value.split('&');
for (Integer i=0; i<parts.size()/2; i++) {
options.add(new SelectOption(EncodingUtil.urlDecode(parts[i*2], 'UTF-8'),
EncodingUtil.urlDecode(parts[(i*2)+1], 'UTF-8')));
}
}
// Backing for hidden text field containing the options from the
// left list
public String leftOptionsHidden { get; set {
leftOptionsHidden = value;
setOptions(leftOptions, value);
}
}
// Backing for hidden text field containing the options from the
// right list
public String rightOptionsHidden { get; set {
rightOptionsHidden = value;
setOptions(rightOptions, value);
}
}
}
=====================
Visualforce Page
=======================
<apex:page controller="MultiselectExampleController" showHeader="false">
<apex:form >
<apex:pageBlock title="Contacts">
<c:MultiselectPicklist leftLabel="Available Contacts" leftOptions="{!allContacts}" rightLabel="Selected Contacts"
rightOptions="{!selectedContacts}" size="14" width="150px"/>
<apex:pageBlockButtons >
<apex:commandButton value="Save" action="{!save}"/>
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
<apex:outputText >{!message}</apex:outputText>
</apex:page>
=================================
Controller for the visualforce page
===============================public with sharing class MultiselectExampleController {
public SelectOption[] selectedContacts { get; set; }
public SelectOption[] allContacts { get; set; }
public String message { get; set; }
public MultiselectExampleController() {
selectedContacts = new List<SelectOption>();
List<Contact> contacts = [SELECT Name, Id FROM Contact];
allContacts = new List<SelectOption>();
for ( Contact c : contacts ) {
allContacts.add(new SelectOption(c.Id, c.Name));
}
}
public PageReference save() {
message = 'Selected Contacts: ';
Boolean first = true;
for ( SelectOption so : selectedContacts ) {
if (!first) {
message += ', ';
}
message += so.getLabel() + ' (' + so.getValue() + ')';
first = false;
}
return null;
}
}
=====================
Ouput:
=========
Good one... its saved my time...
ReplyDeleteAwesome.. Thank you so much
ReplyDeleteIt is not working in lightning mode
ReplyDeleteThere is definately a great deal to know about this subject. I like all of the points you've made. multiselect
ReplyDelete