+ Start a Discussion
Alberto EmpauaAlberto Empaua 

How to use lightning:dualListbox with records retrieved in apex controller

Hi I need help from a Lightning Guru.
I'm trying to use the lightning:dualListbox, the example of salesforce help is pretty easy, link.
What I need is to get the campaigns created in the system to select a few.
Here is my code: Component:
<aura:component access="global" implements="flexipage:availableForAllPageTypes" controller="MassEmailController">
<aura:attribute name="listOptions" type="List"/>
<aura:attribute name="selectedOptions" type="List"/>
<aura:handler name="init" value="{! this }" action="{! c.initialize }"/>
<div class="container slds-card">
    <header class="slds-card__header">
        <div class="slds-path">
            <div class="slds-grid slds-path__track">
                <div class="slds-grid slds-path__scroller-container">
                    <div class="slds-path__scroller" role="application">
                        <div class="slds-path__scroller_inner">
                            <ul class="slds-path__nav" role="listbox" aria-orientation="horizontal">
                                <li class="slds-path__item slds-is-current slds-is-active" role="presentation">
                                    <a aria-selected="true" class="slds-path__link" href="javascript:void(0);" id="path-1" role="option" tabindex="0">
                                        <span class="slds-path__stage">
                                            <!-- svg class="slds-icon slds-icon_x-small" aria-hidden="true">
                                                <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#check" />
                                            </svg -->
                                            <span class="slds-assistive-text">Selected</span>
                                        </span>
                                        <span class="slds-path__title">Campaigns</span>
                                    </a>
                                </li>
                                <li class="slds-path__item slds-is-incomplete" role="presentation">
                                    <a aria-selected="false" class="slds-path__link" href="javascript:void(0);" id="path-2" role="option" tabindex="-1">
                                        <span class="slds-path__stage">
                                            <!-- svg class="slds-icon slds-icon_x-small" aria-hidden="true">
                                                <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#check" />
                                            </svg -->
                                            <span class="slds-assistive-text">Selected</span>
                                        </span>
                                        <span class="slds-path__title">Contacts</span>
                                    </a>
                                </li>
                                <li class="slds-path__item slds-is-incomplete" role="presentation">
                                    <a aria-selected="false" class="slds-path__link" href="javascript:void(0);" id="path-3" role="option" tabindex="-1">
                                        <span class="slds-path__stage">
                                            <!-- svg class="slds-icon slds-icon_x-small" aria-hidden="true">
                                                <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#check" />
                                            </svg -->
                                            <span class="slds-assistive-text">Content</span>
                                        </span>
                                        <span class="slds-path__title">Content</span>
                                    </a>
                                </li>
                            </ul>
                            <div class="slds-path__scroll-controls">
                                <button class="slds-button slds-button_icon slds-button_icon-border-filled" tabindex="-1" title="Scroll left">
                                    <!-- svg class="slds-button__icon" aria-hidden="true">
                                        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#left" />
                                    </svg -->
                                    <span class="slds-assistive-text">Scroll left</span>
                                </button>
                                <button class="slds-button slds-button_icon slds-button_icon-border-filled" tabindex="-1" title="Scroll right">
                                    <!-- svg class="slds-button__icon" aria-hidden="true">
                                        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#right" />
                                    </svg -->
                                    <span class="slds-assistive-text">Scroll right</span>
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </header>
    <div class="slds-card__body slds-card__body_inner">
        <div id="step-campaigns" class="slds-is-expanded">
            <lightning:dualListbox aura:id="selectOptions" name="Select Campaigns"  label="Select Campaigns" 
                       sourceLabel="Available campaigns" 
                       selectedLabel="Selected campaigns" 
                       options="{! v.listOptions }"
                       value="{! v.selectedOptions }"
                       onchange="{! c.handleChange }"/>
        </div>
        <div id="step-contacts" class="slds-is-collapsed">
            <lightning:layout horizontalAlign="start">
                <lightning:layoutItem flexibility="grow">
                    <lightning:input type="email" label="Add recipient" name="email" />
                </lightning:layoutItem>
                <lightning:layoutItem flexibility="shrink">
                    <lightning:buttonIcon iconName="utility:add" variant="neutral" onclick="{! c.handleRecipientAdd }" alternativeText="Add" />
                </lightning:layoutItem>
            </lightning:layout>
            <table id="contacts-table" class="slds-table slds-table_bordered slds-table_resizable-cols slds-table_fixed-layout" role="grid">
                <tr class="slds-line-height_reset">
                     <th class="slds-text-align_right" scope="col" style="width: 3.25rem;">
                         <div class="slds-th__action slds-th__action_form">
                             <span class="slds-checkbox">
                                 <input type="checkbox" name="select-all" id="checkbox-all" tabindex="-1" value="off" />
                                 <label class="slds-checkbox__label" for="checkbox-all">
                                     <span class="slds-checkbox_faux"></span>
                                     <span class="slds-form-element__label slds-assistive-text">Select All</span>
                                 </label>
                             </span>
                         </div>
                    </th>
                    <th aria-sort="none" class="slds-is-resizable slds-text-title_caps" aria-label="Name" scope="col">
                        <span class="slds-truncate" title="First Name">First Name</span>
                    </th>
                    <th aria-sort="none" class="slds-is-resizable slds-text-title_caps" aria-label="Name" scope="col">
                        <span class="slds-truncate" title="Last Name">Last Name</span>
                    </th>
                    <th aria-sort="none" class="slds-is-resizable slds-text-title_caps" aria-label="Name" scope="col">
                        <span class="slds-truncate" title="Company">Company</span>
                    </th>
                    <th aria-sort="none" class="slds-is-resizable slds-text-title_caps" aria-label="Name" scope="col">
                        <span class="slds-truncate" title="Email">Email</span>
                    </th>
                </tr>
            </table>
        </div>
        <div id="step-content" class="slds-is-collapsed">
            <lightning:layout horizontalAlign="start">
                <lightning:layoutItem flexibility="grow">
                    <lightning:select name="select-template" label="Select a Template" required="true">
                    </lightning:select>
                </lightning:layoutItem>
                <lightning:layoutItem flexibility="grow">
                    <lightning:select name="select-sender" label="Select a Sender" required="true">
                    </lightning:select>
                </lightning:layoutItem>
            </lightning:layout>
            <lightning:input type="text" label="Subject" name="subject" />
            <lightning:inputRichText />
        </div>
    </div>
    <footer class="slds-card__footer">
        <lightning:layout horizontalAlign="spread">
            <lightning:layoutItem flexibility="shrink">
                <lightning:button variant="destructive" label="Restart" onclick="{! c.handleRestart }" />
            </lightning:layoutItem>

            <lightning:layoutItem flexibility="shrink">
                <lightning:button variant="neutral" label="Back" onclick="{! c.handleBack }" />
                <lightning:button variant="brand" label="Next" onclick="{! c.handleNext }" />
            </lightning:layoutItem>
        </lightning:layout>
    </footer>
</div>

The important part of component are the attributes and the lightning:dualListbox:
<div id="step-campaigns" class="slds-is-expanded">
            <lightning:dualListbox aura:id="selectOptions" name="Select Campaigns"  label="Select Campaigns" 
                       sourceLabel="Available campaigns" 
                       selectedLabel="Selected campaigns" 
                       options="{! v.listOptions }"
                       value="{! v.selectedOptions }"
                       onchange="{! c.handleChange }"/>
        </div>
Also here is the js controller of the component:
({
initialize: function (component, event, helper) {
    var campaigns = component.get("c.getCampaigns");

    campaigns.setCallback(this, function(response) {

        var state = response.getState();

        if (component.isValid() && state == 'SUCCESS') {                
            component.set("v.listOptions", response.getReturnValue());
        } else {
            console.log('Failed with state: ' + state);
        }
    });

    $A.enqueueAction(campaigns); 

},
handleChange: function (cmp, event) {
    // Get the list of the "value" attribute on all the selected options
    var selectedOptionsList = event.getParam("value");
    alert("Options selected: '" + selectedOptionsList + "'");
}

And my apex controller:
public with sharing class MassEmailController {

    @AuraEnabled
    public static List<Campaign> getCampaigns(){
        system.debug('getCampaigns Controller');
        List<Campaign> cpList = [SELECT  ID,NAME FROM Campaign];

        return cpList;
    }
}

So the problem is that when I assigned the response value to my attribute listOptions that is the parameter of options in the lightning:dualListbox where should go the list of available campaigns. The component is empty and no error is shown.
If someone has a solution and can help me I would appreciate it very much.
Thanks and best regards
 
Best Answer chosen by Alberto Empaua
Alain CabonAlain Cabon
Hello Alberto,

Just change the controller.

options.push({ value: campaign.Name, label: campaign.Name});   could be improved.
 
({
    initialize: function (component, event, helper) {
        var campaigns = component.get("c.getCampaigns");
        campaigns.setCallback(this, function(response) {
            var state = response.getState();
            if (component.isValid() && state == 'SUCCESS') {   
                var campaigns = response.getReturnValue();
                var options = [];
                campaigns.forEach(function(campaign)  { 
                    console.log(campaign);
                    options.push({ value: campaign.Name, label: campaign.Name});
                });
                component.set("v.listOptions", options);
            } else {
                console.log('Failed with state: ' + state);
            }
        });
        $A.enqueueAction(campaigns); 
    },
    handleChange: function (cmp, event) {
        // Get the list of the "value" attribute on all the selected options
        var selectedOptionsList = event.getParam("value");
        alert("Options selected: '" + selectedOptionsList + "'");
    }
})


User-added image

Cheers
Alain

All Answers

Alain CabonAlain Cabon
Hello Alberto,

Just change the controller.

options.push({ value: campaign.Name, label: campaign.Name});   could be improved.
 
({
    initialize: function (component, event, helper) {
        var campaigns = component.get("c.getCampaigns");
        campaigns.setCallback(this, function(response) {
            var state = response.getState();
            if (component.isValid() && state == 'SUCCESS') {   
                var campaigns = response.getReturnValue();
                var options = [];
                campaigns.forEach(function(campaign)  { 
                    console.log(campaign);
                    options.push({ value: campaign.Name, label: campaign.Name});
                });
                component.set("v.listOptions", options);
            } else {
                console.log('Failed with state: ' + state);
            }
        });
        $A.enqueueAction(campaigns); 
    },
    handleChange: function (cmp, event) {
        // Get the list of the "value" attribute on all the selected options
        var selectedOptionsList = event.getParam("value");
        alert("Options selected: '" + selectedOptionsList + "'");
    }
})


User-added image

Cheers
Alain
This was selected as the best answer
Alberto EmpauaAlberto Empaua
Hi Alain,
Thanks for the help!, it's working perfectly now. 
Alain CabonAlain Cabon
Good. You have written a nice piece of code by the way. Have a nice day!
Alain CabonAlain Cabon
options.push({ value: campaign.Id, label: campaign.Name});

should be better for a real unique key of the options if you have duplicate campaign names, the selected value is not readable with the id but it  would be unique.
Nuevo9763Nuevo9763
Hi Alain Cabon,
I am converting existing VF pages to LEX using 'lightningStyleSheets' attribute.
I have an input field rendered as multi-select picklist. Upon rendering page right arrow and left arrow buttons do not function. Please note that I am not writing lightning component. Can you suggest solution? Do I have to write slds style tags and/or javascript for this input field? For other controls on the page like select lists, I didn'y have to wrote any code, the lightningStyleSheets="true" took care of everythhing.