TransWikia.com

Lightning Component - Picklist Field with Ability to write free text

Salesforce Asked by Giorgos Galaios on December 2, 2020

I need to override standard Create and Edit Actions on Account object with Lightning Component. Is there a way or a type of field that we could cover the following requirement?
Have a field with some predifined values but letting user if he wants to enter free text. I would actually like something like Subject field on Task object but i cannot find any way to implement it. Any ideas please ?

Example: I have a picklist field for Citizenship that has some values for Countries (England, Germany, France, …etc…). But i want to let user enter his own value (for example: German). i have tried using the following but without success:

<!--05/09/2019 George Galaios: Code for Iteration Picklist: Citizenship -->
                        <lightning:select aura:id="accCitizenship" label="{!$Label.c.ea_citizenship}" value="{!v.accountRecord.ea_Citizenship__c}" disabled="{!and(v.noExtraPermission, v.noPermAndCleansed)}" class="slds-size--1-of-2 slds-p-horizontal_x-small">
                            <aura:iteration items="{!v.ea_Citizenship_Values}" var="item">
                                <option value="{!item}" selected="{!item==v.accountRecord.ea_Citizenship__c}">{!item}</option>
                            </aura:iteration>
                        </lightning:select>                
                        <!-- End of Code for Iteration -->

15/11/2020 UPDATE: I update my question with my solution, in order to help someone with the same issue.

Component

<!--27/10/2019 George Galaios: This component is created in order to cover Citizenship fields. Those fields are not restricted picklists, so it is needed to accept either values from Picklists or Free Text! -->
<!--27/10/2019 George Galaios: Define the appopriate Attributes.-->
<aura:component controller="ea_PickListController">
    <aura:attribute name="objectName" type="String" default="Account"/>
    <aura:attribute name="fieldName" type="String" default="ea_Citizenship__c"/>
    <aura:attribute name="selectRecordId" type="String"/>
    <aura:attribute name="selectRecordName" type="String"/>
    <aura:attribute name="Label" type="String" default="{!$Label.c.ea_citizenship}"/>
    <aura:attribute name="picklistValues" type="String[]"/>
    <aura:attribute name="allListValues" type="String[]"/>
    <aura:attribute name="required" type="Boolean" default="false"/>
    <aura:attribute name="iconName" type="String" default="utility:identity"/>
    <aura:attribute name="LoadingText" type="Boolean" default="false"/>
    <aura:attribute name="readonly" type="Boolean" default="false"/>
    <aura:attribute name="helpText" type="String" default="Επιλέξτε μία χώρα από την λιστα είτε πληκτρολογήστε μία τιμή της επιλογής σας"/>
    
    <!--27/10/2019 George Galaios: If focus goes out, call closeDropDown Controller function-->
    <div onfocusout="{!c.closeDropDown}">         
        <div class="slds-combobox_container slds-size--1-of-1 slds-p-horizontal_x-small">
            
            <div class="slds-size--1-of-1 slds-p-horizontal_x-small slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click" aura:id="resultBox" aria-expanded="false" aria-haspopup="listbox" role="combobox">
                <div class="slds-form-element__control" role="none">
                    <aura:if isTrue="{!v.readonly}">
                        
                        <!--27/10/2019 George Galaios: Input Field for Citizenship. When user typing, call searchField Controller function-->                    
                        <lightning:input required="{!v.required}" disabled="{!v.readonly}" aura:id="userinput" label="{!v.Label}" name="searchText" value="{!v.selectRecordName}" fieldLevelHelp="{!v.helpText}" class="leftspace"/>
                        
                        <aura:set attribute = "else">
                            <!--27/10/2019 George Galaios: Input Field for Citizenship. When user typing, call searchField Controller function-->                    
                            <lightning:input required="{!v.required}" disabled="{!v.readonly}" aura:id="userinput" label="{!v.Label}" name="searchText" onchange="{!c.searchField}" onclick="{!c.getPickListValues}" value="{!v.selectRecordName}" isLoading="{!v.LoadingText}" type="search" fieldLevelHelp="{!v.helpText}" class="leftspace"/></aura:set>
                        
                    </aura:if>
                    
                </div>
                
                <!--27/10/2019 George Galaios: Second part display result -->
                <div id="listbox-id-1" class="slds-dropdown slds-dropdown_length-with-icon-7 slds-dropdown_fluid" role="listbox">
                    <ul class="slds-listbox slds-listbox_vertical" role="presentation" >
                        <aura:iteration items="{!v.picklistValues}" var="serecord" indexVar="hdtv">
                            <li role="presentation" class="slds-listbox__item">
                                <!--27/10/2019 George Galaios: Show the list of values that match user's typed criteria. Onmousedown call setSelectedRecord controller function  -->
                                <div data-name="{!serecord}" onmousedown="{!c.setSelectedRecord}"  class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta" role="option">
                                    <span class="slds-media__figure">
                                        <span class="slds-icon_container slds-icon-standard-account">
                                            <!--27/10/2019 George Galaios: Show icon on the left of results displayed  -->                                            
                                            <lightning:icon iconName="{!v.iconName}" class="slds-icon slds-icon slds-icon_small slds-icon-text-default" size="x-small"/>
                                        </span>
                                    </span>
                                    <span class="slds-media__body">
                                        <!--27/10/2019 George Galaios: Display Countries Names  -->
                                        <span class="slds-listbox__option-text slds-listbox__option-text_entity">{!serecord}</span>
                                    </span>
                                </div>
                            </li>
                        </aura:iteration>
                        
                        <!--27/10/2019 George Galaios: If loading, show the appropriate message on the screen  -->
                        <aura:if isTrue="{!v.LoadingText}">
                            Loading...
                        </aura:if>
                    </ul>
                </div>
            </div>                                          
        </div>
    </div>           
</aura:component>

Controller

//ggalaios @ 27/10/2019 
//Lightning Component for Citizenships fields of Account
//Component Controller

({
    //When clicking on the component it calls Apex function that fetches the values of the picklist field that is given
    getPickListValues : function(component) {
        //Check if field is in ReadOnly mode and confirm that it does not already have a value
        if ((component.get("v.readonly") == false) && ((component.get("v.selectRecordName") == "" || component.get("v.selectRecordName") == undefined || component.get("v.selectRecordName") == null))) {
            component.set("v.LoadingText", true);
            var action = component.get("c.getPickListValuesIntoList");
            action.setParams({
                //set the appropriate params
                "objectType": component.get("v.objectName"),
                "selectedField": component.get("v.fieldName")
            });
            action.setCallback(this, function(response) {
                var list = response.getReturnValue();
                component.set("v.picklistValues", list);
                component.set("v.allListValues", list);
                component.set("v.LoadingText", false);
                var resultBox = component.find('resultBox');
                $A.util.addClass(resultBox, 'slds-is-open');
                //console.log('return value: ' +response.getReturnValue());
            })
            $A.enqueueAction(action);
        }
    },
    
    //Function called while user typing on input field
    searchField : function(component, event, helper) {
        //Capitalize input
        component.set("v.LoadingText", true);
        var currentText = helper.RemoveAccentsAndCapitalize(event.getSource().get("v.value"));
        //Capitalize Component attribute
        component.set("v.selectRecordName", currentText);
        var resultBox = component.find('resultBox');
        //if length of text typed by user > 0 show resultBox, else not show it and assign again PickListValues Attriute the whole list of values
        if(currentText.length > 0) {
            $A.util.addClass(resultBox, 'slds-is-open');
            //Call Apex Class to return the results while user is typing
            //console.log('Just before calling Apex... current Text is: ' +currentText);
            var action = component.get("c.getSearchList");
            action.setParams({
                "citizenshipList" : component.get("v.allListValues"),
                "value" : currentText
            });
            action.setCallback(this, function(response){
                var STATE = response.getState();
                if(STATE === "SUCCESS") {
                    //console.log('from function is returned...: ' +response.getReturnValue());
                    component.set("v.picklistValues", response.getReturnValue());
                    component.set("v.LoadingText", false);
                    if(component.get("v.picklistValues").length == 0) {
                        $A.util.removeClass(resultBox, 'slds-is-open');
                    }
                }
                else if (state === "ERROR") {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            console.log("Error message: " + 
                                        errors[0].message);
                        }
                    } else {
                        console.log("Unknown error");
                    }
                }
            });
            $A.enqueueAction(action);
        }
        else {
            component.set("v.LoadingText", true);
            //console.log('case is currentText is zero length');
            var action = component.get("c.getPickListValuesIntoList");
            action.setParams({
                //set the appropriate params
                "objectType": component.get("v.objectName"),
                "selectedField": component.get("v.fieldName")
            });
            action.setCallback(this, function(response) {
                var list = response.getReturnValue();
                component.set("v.picklistValues", list);
                component.set("v.allListValues", list);
                var resultBox = component.find('resultBox');
                component.set("v.LoadingText", false);
                $A.util.addClass(resultBox, 'slds-is-open');
            })
            $A.enqueueAction(action);
        }
    },
    
    //when user clicks (X) button, set the appropriate Attributes blank.
    resetData : function(component, event, helper) {
        component.set("v.LoadingText", true);
        component.set("v.selectRecordName", "");
        component.find('userinput').set("v.readonly", false);
        component.set("v.LoadingText", false);
    },
    
    //When user selects a record, set it as selected
    setSelectedRecord : function(component, event, helper) {
        var currentText = event.currentTarget.id;
        var resultBox = component.find('resultBox');
        $A.util.removeClass(resultBox, 'slds-is-open');
        component.set("v.selectRecordName", event.currentTarget.dataset.name);
    }, 
    
    //Function when user clicks outside Component to close the dropdown list
    closeDropDown : function(component, event, helper) {
        var resultBox = component.find('resultBox');
        $A.util.removeClass(resultBox, 'slds-is-open');
        component.set("v.LoadingText", false);
    },
    
    
})

Helper

({
    RemoveAccentsAndCapitalize: function(strAccents) {
        var strAccents = strAccents.split('');
        var strAccentsOut = new Array();
        var strAccentsLen = strAccents.length;
        var accents = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽžάέήύόύϋΰίϊΐώΆΈΉΎΌΆΎΊΏ';
        var accentsOut = "AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZzαεηυουϋϋιϊϊωαεηυοαυιω";
        for (var y = 0; y < strAccentsLen; y++) {
            if (accents.indexOf(strAccents[y]) != -1) {
                strAccentsOut[y] = accentsOut.substr(accents.indexOf(strAccents[y]), 1);
            } else
                strAccentsOut[y] = strAccents[y];
        }
        strAccentsOut = strAccentsOut.join('');
        return strAccentsOut.toUpperCase(); //@ggalaios return string also capitalized
    },
})

Style

.THIS .slds-leftpad{
    padding-left: 2rem;
}
.THIS .iconheight{
    top: 65%;
}

.THIS .leftspace input {
    padding-left:2rem;
}

Apex Class Controller

public class ea_PickListController {
    @AuraEnabled
    //15/09/2019: George Galaios: Method to get Picklist values
    public static List<String> getPickListValuesIntoList(String objectType, String selectedField){
        List<String> pickListValuesList = new List<String>();
        Schema.SObjectType convertToObj = Schema.getGlobalDescribe().get(objectType);
        Schema.DescribeSObjectResult res = convertToObj.getDescribe();
        Schema.DescribeFieldResult fieldResult = res.fields.getMap().get(selectedField).getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
        //27/10/2019: ggalaios: Check if SelectedField is different than Citizenships. Because in Citizenships we do not want the Choice "Please Select"
        if ((selectedField != 'ea_Citizenship__c') && (selectedField != 'ea_Citizenship2__c') && (selectedField != 'ea_Profession__c')) {
            pickListValuesList.add('--Παρακαλώ Επιλέξτε--');
        }
        for( Schema.PicklistEntry pickListVal : ple){
            pickListValuesList.add(pickListVal.getLabel());
        }     
        return pickListValuesList;
    }
    
    @AuraEnabled
    //27/10/2019 George Galaios: This method is called while user is typing (searching for Citizenship)
    public static List<String> getSearchList(List<String> citizenshipList, String value) {
        //Initiate the list that is going to be returned
        List<String> searchResultList = new List<String>();
        try {
            //for every item of the list check if what user has typed is contained in the List of Citizenships
            for (Integer i=0; i<citizenshipList.size(); i++) {
                if (citizenshipList[i].contains(value)) {
                    searchResultList.add(citizenshipList[i]);
                }
            }
        } catch (Exception e) {
            system.debug('exception caught: ' +e.getMessage());
        }
        return searchResultList;
    }
}

Apex Class Controller Test

@isTest
//Test class for ea_PickListController Apex Class
public class ea_PickListControllerTest {
    @isTest Public static void getPickListValuesIntoListTest() {
        ea_PickListController.getPickListValuesIntoList('Account', 'ea_CustomerType__c');
    }
    
    //Test getSearchList method
    @isTest public static void getSearchListTest() {
        List<String> testList = new List<String>();
        testList.add('ΑΓΓΛΙΑ');
        testList.add('ΕΛΛΑΔΑ');
        testList.add('ΗΝΩΜΕΝΕΣ ΠΟΛΙΤΕΙΕΣ ΑΜΕΡΙΚΗΣ');
        ea_PickListController.getSearchList(testList, 'ΕΛΛ');
    }
}

2 Answers

Finally i gave solution to my problem by creating a new Lightning Component and including it to the Lightning Component for Account. This component i created has an input field as well as a dropdown list to show the available list items. Onclick, the dropdown gets displayed and onfocusout it gets disappeared. Also, the inputField has an action onchange in order to call Apex Class controller to filter the results while user is Typing!

Correct answer by Giorgos Galaios on December 2, 2020

You can give last option as "Other" to select value. Once other value is selected you can render input field where a user can enter text value. Before mapping, you need to check if the value is "Other" you need to consider input field.

Answered by Chetan Nandre on December 2, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP