Custom Lookup is a very useful component if you are creating a custom form or custom component with editable fields. Rest all field type components like input, combobox, checkbox, textarea are available but for lookup, you need to create one.
Custom Lookup is a small component and very easy to create. We will create this within a single component without using any child component or event. You can find the complete source code at the bottom of the page.
Custom Lookup component Features:
- Single component
- Will work on any object
- Spinner to show processing
- Ability to set sObject Icon
- Option to set placeholder & label
- Ability to show error in the dropdown if any occurs.
Demo GIF:
Also Check, Custom Lookup using Aura Lightning
Also Check, Multi-Select Lookup Lightning Component
Step-1: Create an Apex controller
Our apex controller will fetch records on passing object and fields name to it. Here we are using a wrapper class which will return records in the form of value and label.
Create CustomLookupController.cls Apex class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Code by CafeForce || www.cafeforce.com || support@cafeforce.com || Mandatory Header */ public with sharing class CustomLookupController { @AuraEnabled public static List<RecordsData> fetchRecords(String objectName, String filterField, String searchString, String value) { try { List<RecordsData> recordsDataList = new List<RecordsData>(); String query = 'SELECT Id, ' + filterField + ' FROM '+objectName; if(String.isNotBlank(value)) { query += ' WHERE Id = \''+ value + '\' LIMIT 49999'; } else { query += ' WHERE '+filterField+ ' LIKE ' + '\'' + String.escapeSingleQuotes(searchString.trim()) + '%\' LIMIT 49999'; } for(SObject s : Database.query(query)) { recordsDataList.add( new RecordsData((String)s.get(filterField), (String)s.get('id')) ); } return recordsDataList; } catch (Exception err) { if ( String.isNotBlank( err.getMessage() ) && err.getMessage().contains( 'error:' ) ) { throw new AuraHandledException(err.getMessage().split('error:')[1].split(':')[0] + '.'); } else { throw new AuraHandledException(err.getMessage()); } } } public class RecordsData { @AuraEnabled public String label; @AuraEnabled public String value; public RecordsData(String label, String value) { this.label = label; this.value = value; } } } /* Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE */ |
Step-2: Now we will create the CustomLookup Lightning Web Component.
For creating a new LWC component, you need to use the VS Code IDE.
Markup for customLookup.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<!-- Code by CafeForce || www.cafeforce.com || support@cafeforce.com || Mandatory Header --> <template> <div class={className}> <template if:true={label}> <p class="slds-form-element__label"> <template if:true={required}> <span class="requiredAsterisk">*</span> </template> {label} </p> </template> <div class="slds-combobox_container" aria-expanded="true" aria-haspopup="listbox" role="combobox"> <div class="slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open"> <!-- Search Input Box --> <template if:false={showPill}> <lightning-input onchange={searchRecords} onclick={showRecords} onblur={blurEvent} class="inputBox" type="search" autocomplete="off" variant="label-hidden" placeholder={placeholder}></lightning-input> <div if:true={showSpinner}> <lightning-spinner alternative-text="Loading" size="small"></lightning-spinner> </div> </template> <!-- Selected Value Pill --> <div if:true={showPill} class="pillContainer"> <lightning-pill class="fullWidth" label={selectedRecord.label} name={selectedRecord.value} onremove={removeItem}> <lightning-icon icon-name={iconName} alternative-text="icon" size="x-small"></lightning-icon> </lightning-pill> </div> <!-- Dropdown List --> <template if:true={showDropdown}> <div class="slds-dropdown slds-dropdown_length-5 slds-dropdown_fluid" > <ul class="slds-listbox slds-listbox_vertical recordListBox" > <template if:false={message} > <template for:each={recordsList} for:item="rec"> <li key={rec.value} data-key={rec.value} class="slds-listbox__item eachItem" onmousedown={selectItem}> <div class="slds-media slds-listbox__option_entity"> <lightning-icon icon-name={iconName} alternative-text="icon" size="small"></lightning-icon> <span class="verticalAlign slds-truncate">{rec.label}</span> </div> </li> </template> </template> <template if:true={message} > <li class="slds-listbox__item"> <span class="slds-media slds-listbox__option_entity">{message}</span> </li> </template> </ul> </div> </template> </div> </div> </div> </template> <!-- Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE --> |
Now open the javascript file customLookup.js and paste the below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
/* Code by CafeForce || www.cafeforce.com || support@cafeforce.com || Mandatory Header */ import { LightningElement, api, track } from 'lwc'; import fetchRecords from '@salesforce/apex/CustomLookupController.fetchRecords'; export default class CustomLookup extends LightningElement { @api objectName; @api fieldName; @api value; @api iconName; @api label; @api placeholder; @api className; @api required = false; @track searchString; @track selectedRecord; @track recordsList; @track message; @track showPill = false; @track showSpinner = false; @track showDropdown = false; connectedCallback() { if(this.value) this.fetchData(); } searchRecords(event) { this.searchString = event.target.value; if(this.searchString) { this.fetchData(); } else { this.showDropdown = false; } } selectItem(event) { if(event.currentTarget.dataset.key) { var index = this.recordsList.findIndex(x => x.value === event.currentTarget.dataset.key) if(index != -1) { this.selectedRecord = this.recordsList[index]; this.value = this.selectedRecord.value; this.showDropdown = false; this.showPill = true; } } } removeItem() { this.showPill = false; this.value = ''; this.selectedRecord = ''; this.searchString = ''; } showRecords() { if(this.recordsList && this.searchString) { this.showDropdown = true; } } blurEvent() { this.showDropdown = false; } fetchData() { this.showSpinner = true; this.message = ''; this.recordsList = []; fetchRecords({ objectName : this.objectName, filterField : this.fieldName, searchString : this.searchString, value : this.value }) .then(result => { if(result && result.length > 0) { if(this.value) { this.selectedRecord = result[0]; this.showPill = true; } else { this.recordsList = result; } } else { this.message = "No Records Found for '" + this.searchString + "'"; } this.showSpinner = false; }).catch(error => { this.message = error.message; this.showSpinner = false; }) if(!this.value) { this.showDropdown = true; } } } /* Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE */ |
Now finally paste the CSS in the customLookup.css file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
.verticalAlign { cursor: pointer; margin: 4px 0px 0px 6px!important; } .fullWidth { width: 100% !important; } .eachItem:hover { background-color: #EEE; cursor: pointer; } .slds-listbox__option_entity { padding: .1.6rem .75rem !important; } .requiredAsterisk { color: rgb(194, 57, 52); font-size: 12px; padding-right: 2px; } .pillContainer{ border: 1px solid #d9dbdd; border-radius: 4px; line-height: 0.5rem; padding: 2px; } /* For Scrolling */ ::-webkit-scrollbar { width: 7px; height: 7px; } ::-webkit-scrollbar-track { display: none !important; } ::-webkit-scrollbar-thumb { border-radius: 10px; background: rgba(0,0,0,0.4); } |
Step-3: Now we will call the component.
1 2 3 4 5 6 |
<!-- Code by CafeForce || www.cafeforce.com || support@cafeforce.com || Mandatory Header --> <aura:application extends="force:slds"> <c:customLookup objectName="Account" fieldName="Name" label="Account Search" placeholder="search Account" iconName="standard:account"></c:customLookup> </aura:application> |
Finally, our component is ready to use. Now while calling this component, you need to pass the objectName, fieldName, and iconName (optional) to this custom component. You can also set additional attributes.
You can check the list of available icons here LDS Icons.
Update
Code Updated. Required and className attributes are added to the component. className will add SLDS class to the outermost div. Required is a boolean attribute, on setting true, an asterisk icon will be shown before the label.
Also Check:
For any queries or suggestions, comment below.
Cheers … Happy Coding … 🙂
I can’t be able to search by typing anything in the lookup field.
Hi Ayushi,
Please check debug logs as to what error is coming. Also, add some debugs in Apex code to check if records are returned from SOQL or not.
Yes Thanks that’s sorted out. Could you please tell me here currently we were searching only from one field. If i want to search with many fields how can i do?
How to get only active users and excluding few profiles in the dynamic soql query?
Please let us know
Hi Mahesh,
You can put WHERE filter in query as
[SELECT Id FROM User WHERE isActive = true AND Profile.Name != ‘Standard User’]