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, 'ΕΛΛ');
}
}