Thursday, April 18, 2019

Custom Lookup/Autocomplete with Event Bubbling and Wire Method to Function

Hello Guys, hope you are doing great!

This post explains the basic use case of custom Lookup/Autocomplete with Lightning web components. This component uses the Event bubbling and with Wire method to function.

Here is the sample, how it will look. This generic lookup can be used with any object. Just pass on the SObject name and some parameters, it will be available to use. 





Example:
     <c-lookup-search label="Custom Lookup - Account" selectedsobject="Account" 
       recordlimit="10" onlookupselect={handlelookupselectaccount}></c-lookup-search>  

Lets see the details component wise.

The following component will hold a lookup option element. Click on the option will fire a bubbling event. This event will be caught by parent and grandparent components.

The event will pass the selected record in the details.



lookupItem.html

 <template>  
   <template if:true={record}>  
     <lightning-layout vertical-align="center">  
       <div style="cursor:pointer" key={record.Id} data-contact-id={record.Id} onclick={handleSelect}>  
         <lightning-layout-item padding="around-small">  
           {record.Name}  
         </lightning-layout-item>  
       </div>  
     </lightning-layout>  
   </template>  
   <template if:false={record}>  
     <p>No contact data available.</p>  
   </template>  
 </template>  


lookupItem.js

 import { LightningElement, api } from 'lwc';  
 export default class LookupItem extends LightningElement {  
   @api record;  
   // This method handles the selection of lookup value  
   handleSelect(event) {  
     // Event will be triggerred and bubbled to parent and grandparent.  
     // Check the parameters passed.  
     const selectEvent = new CustomEvent('lookupselect', {  
       detail: this.record,  
       bubbles: true,  
       composed: true  
     });  
     // Fire the custom event  
     this.dispatchEvent(selectEvent);  
   }  
 }  


The following component will hold an input text to search the lookup. It will do the server side Apex call to get the records. Apex call is generic so it can accommodate any SObject. Records will be then iterated over lookup-item component which we created in the earlier step.

Note: Currently this component searches the text on Name field of the SObject. But we can change/make it generic.

lookupSearch.html

 <template>  
     <div class="slds-m-around_medium selectoptions">  
         <lightning-input class="slds-m-bottom_small" label="Search" value={selectedName} minlength="1" isloading=true onkeyup={handleKeyChange}>  
         </lightning-input>  
       <template if:true={showoptions}>  
           <template if:true={records}>  
             <template for:each={records} for:item="record">  
               <template if:true={record}>  
                 <c-lookup-item key={record.Id} record={record} onlookupselect={handlelookupselect}>  
                 </c-lookup-item>  
               </template>  
             </template>  
           </template>  
         <template if:true={noRecordsFlag}>  
           <p>'{searchString}' in {label}s</p>  
         </template>  
       </template>  
     </div>  
 </template>  


lookupSearch.js


 import { LightningElement, track, api, wire} from 'lwc';  
 import getLookupSerachRecords from '@salesforce/apex/ManageRecordsController.getLookupSerachRecords';  
 export default class LookupSearch extends LightningElement {  
   // Tracked properties  
   @track records;  
   @track noRecordsFlag = false;  
   @track showoptions = true;  
   @track searchString = '';  
   @track selectedName;  
   // API properties  
   @api selectedsobject;  
   @api recordlimit;  
   @api label;  
   // Wire method to function, which accepts the Search String, Dynamic SObject, Record Limit, Search Field  
   @wire(getLookupSerachRecords, { searchString: '$searchString' , selectedSObject : '$selectedsobject', recordLimit : '$recordlimit'})  
   wiredContacts({ error, data }) {  
     this.noRecordsFlag = 0;  
     if (data) {  
       this.records = data;  
       this.error = undefined;  
       this.noRecordsFlag = this.records.length === 0 ? true : false;  
     } else if (error) {  
       this.error = error;  
       this.records = undefined;  
     }  
   }  
   // handle event called lookupselect  
   handlelookupselect(event){  
     this.selectedName = event.detail.Name;  
     this.showoptions = false;  
   }  
   // key change on the text field  
   handleKeyChange(event) {  
     this.showoptions = true;  
     this.searchString = event.target.value;  
   }  
 }  


lookupSearch.css

 lightning-input,  
 c-lookup-item {  
   position: relative;  
   border: solid 1px #ecebea;  
   border-radius: 4px;  
   display: block;  
   padding: 2px;  
 }  
 c-lookup-item {  
   margin: 1px 0;  
 }  
 lightning-input:before,  
 c-lookup-item:before,  
 selectoptions:before {  
   color: #dddbda;  
   position: absolute;  
   top: -9px;  
   left: 4px;  
   background-color: #ffffff;  
   padding: 0 4px;  
 }  
 selectoptions {  
   border: solid 1px #ecebea;  
 }  

We are done with our web component implementation, now its time to use it.

You can see that we have included the lookup-search component with the parameters. Parameters are pretty easy and straight forward. 

label                     : Label to be shown on the UI
selectedsobject     : SObject from which data to be fetched.
recordlimit            : Number of records to be fetched.

Please check .js file, handlers will give you the selected record. The selected lookup record can be used for your further operations.



lookupWrapperParent.html


 <template>  
   <lightning-card title="Custom Lookup - Account" icon-name="custom:custom57">  
     <c-lookup-search label="Custom Lookup - Account" selectedsobject="Account"   
       recordlimit="10"    
       onlookupselect={handlelookupselectaccount}></c-lookup-search>  
     <tempate if:true={selectedAccountRecord}>  
       <p>SELECTED RECORD ID : {selectedAccountRecord.Id}</p>  
       <p>SELECTED RECORD VALUE : {selectedAccountRecord.Name}</p>  
     </tempate>  
   </lightning-card>  
   <lightning-card title="Custom Lookup - Contact" icon-name="custom:custom57">  
     <c-lookup-search label="Contact" selectedsobject="Contact" recordlimit="10"  
        onlookupselect={handlelookupselectcontact}>  
     </c-lookup-search>  
     <tempate if:true={selectedContactRecord}>  
       <p>SELECTED RECORD ID : {selectedContactRecord.Id}</p>  
       <p>SELECTED RECORD VALUE : {selectedContactRecord.Name}</p>  
     </tempate>  
   </lightning-card>  
 </template>  


lookupWrapperParent.js

 import { LightningElement, track } from 'lwc';  
 export default class LookupWrapperParent extends LightningElement {  
   @track selectedAccountRecord;  
   @track selectedContactRecord;  
   // Event bubbles to grandparent and being handled here - Account  
   handlelookupselectaccount(event) {  
     this.selectedAccountRecord = event.detail;  
   }  
   // Event bubbles to grandparent and being handled here - Contact  
   handlelookupselectcontact(event) {  
     this.selectedContactRecord = event.detail;  
   }  
 }  


Apex class 

ManageRecordsController.cls

 public with sharing class ManageRecordsController {  
   @AuraEnabled(cacheable=true)  
   public static List<Account> getLookupSerachRecords(String searchString, String selectedSObject, Integer recordLimit) {  
     if(searchString != null && searchString != ''){  
       String query = 'select Name, Id from ' + selectedSObject;  
         query += ' where Name like \'%'+ searchString +'%\' ';  
       query+= ' limit ' + recordLimit;  
       return Database.query(query);  
     }  
     return null;  
   }  
 }  
It was a simple example which shows the custom lookup or Autocomplete with Event Bubbling and Wire Method to Function.


I hope you enjoyed the learning, please write me back the suggestions, comments or any issues. Let's meet in our next post with more learnings and fun. :)

THANK YOU!

4 comments:

  1. what is this tempate in the final "lookupWrapperParent.html"?

    ReplyDelete
  2. That's really awesome blog because i found there lot of valuable Information.buy flyer templates

    ReplyDelete
  3. I Toilet Plungers even have have} to say I'm concerned when I see superficial articles like this that don't actually have nuance. Or that mSLA printers are generally simpler to repair end result of} less transferring elements. Or that print orientation affects bodily properties of FDM but has less results on SLA. Also there are water washable resins that don't need alcohol for cleaning. Like either you assume people are experts and don't bring up the differences or assume people are beginners and give sufficient information for them to make an informed choice.

    ReplyDelete

Salesforce: Export to Excel with Lightning Web Component

Hello Guys, I hope you are doing well. In this post, we are going to see an implementation of " Export to Excel" in lightn...