+ Start a Discussion
SFDC coderSFDC coder 

how to create reusable lightning lookup with dynamic fields to display?

I have a use case where in i need to develop a reusable lightning component but with dynamic fields to display
For eg: the lookup component should display A,B,C fields in one part and
X,Y,Z fields on another part in the same application
how can i achieve this using one component only?

Any help would be appreciated
 
NagendraNagendra (Salesforce Developers) 
Hi,
Create Apex Class Controller.
Apex class [customLookUpController.apxc]
public class customLookUpController {
    @AuraEnabled
    public static List < sObject > fetchLookUpValues(String searchKeyWord, String ObjectName) {
        system.debug('ObjectName-->' + ObjectName);
        String searchKey = searchKeyWord + '%';
        
        List < sObject > returnList = new List < sObject > ();
      
        // Create a Dynamic SOQL Query For Fetch Record List with LIMIT 5   
        String sQuery =  'select id, Name from ' +ObjectName + ' where Name LIKE: searchKey order by createdDate DESC limit 5';
        List < sObject > lstOfRecords = Database.query(sQuery);
        
        for (sObject obj: lstOfRecords) {
            returnList.add(obj);
        }
        return returnList;
    }
}
  • In above Apex class we have only one @AuraEnabled Method.
  • In this method we have 2 String ‘searchKeyWord’ and ‘ObjectName’ parameter.
  • By this parameter we are find sObject record List and Return the list.
 Step 2 : Create Lightning Event
  • Next we create a Lightning Event bundle for communicate data(attribute values) between different components. (Child To Parent Component )
  • Events are contain attributes that can be set before the event is fired and read when the event is handled by component.

from developer console >> file >> new >> Lightning Event >> enter name >> selectedsObjectRecordEvent >> save

lightning Event [selectedsObjectRecordEvent.evt]

<aura:event type="COMPONENT" description="by this event we are pass the selected sObject(lookup list record) in the parent component">
    <aura:attribute name="recordByEvent" type="sObject"/>
</aura:event>
  • In above Event we have only single attribute which type is sObject type.
  • by this attribute, we are passing the selected Object record to parent component [ CustomLookup ]  by child component[customLookupResult ].

Component Blue Print 

User-added image
Step 3 : Create Child Component For Display the Search Result List
Lightning Component [customLookupResult.cmp] 
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
	<aura:attribute name="oRecord" type="sObject" />
        <aura:attribute name="IconName" type="string"/> 
 
  <!--Register the component level event-->
    <aura:registerEvent name="oSelectedRecordEvent" type="c:selectedsObjectRecordEvent"/>
 
    <li role="presentation" class="slds-listbox__item" onclick="{!c.selectRecord}">
        <span id="listbox-option-unique-id-01" 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" title="Description of icon when needed">
                    <lightning:icon iconName="{!v.IconName}" class="slds-icon slds-icon_small" size="small" alternativeText="icon"/>
                    <span class="slds-assistive-text">Description of icon</span>
                  </span>
              </span>    
              <span class="slds-media__body">  
                  <span class="slds-listbox__option-text slds-listbox__option-text_entity">{!v.oRecord.Name}</span>
              </span>
        </span>
    </li>
</aura:component>
JS Controller [customLookupResultController.js]
({
   selectRecord : function(component, event, helper){      
    // get the selected record from list  
      var getSelectRecord = component.get("v.oRecord");
    // call the event   
      var compEvent = component.getEvent("oSelectedRecordEvent");
    // set the Selected sObject Record to the event attribute.  
         compEvent.setParams({"recordByEvent" : getSelectRecord });  
    // fire the event  
         compEvent.fire();
    },
})
Step 4 : Create Lightning Custom Lookup Component [Parent]
Lightning Component [customLookup.cmp]
<aura:component controller="customLookUpController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
    <!--declare attributes--> 
    <aura:attribute name="selectedRecord" type="sObject" default="{}" description="Use,for store SELECTED sObject Record"/>
    <aura:attribute name="listOfSearchRecords" type="List" description="Use,for store the list of search records which returns from apex class"/>
    <aura:attribute name="SearchKeyWord" type="string"/>
    <aura:attribute name="objectAPIName" type="string" default=""/>
    <aura:attribute name="IconName" type="string" default=""/>
    <aura:attribute name="label" type="string" default=""/>
    <aura:attribute name="Message" type="String" default=""/>
    
    <!--declare events hendlers-->  
    <aura:handler name="oSelectedRecordEvent" event="c:selectedsObjectRecordEvent" action="{!c.handleComponentEvent}"/>
   
    
    <!-- https://www.lightningdesignsystem.com/components/lookups/ --> 
    
    <div onmouseleave="{!c.onblur}" aura:id="searchRes" class="slds-form-element slds-lookup slds-is-close" data-select="single">
        <label class="slds-form-element__label" for="lookup-348">{!v.label}</label>
        <!--This part is for display search bar for lookup-->  
        <div class="slds-form-element__control">
            
            <div class="slds-input-has-icon slds-input-has-icon--right">
              <lightning:icon class="slds-input__icon slds-show" iconName="utility:search" size="x-small" alternativeText="search"/> 
                <!-- This markup is for when an record is selected -->
                <div aura:id="lookup-pill" class="slds-pill-container slds-hide">
                     <lightning:pill class="pillSize" label="{!v.selectedRecord.Name}" name="{!v.selectedRecord.Name}" onremove="{! c.clear }">
                          <aura:set attribute="media">
                             <lightning:icon iconName="{!v.IconName}" size="x-small" alternativeText="{!v.IconName}"/>
                          </aura:set>
                      </lightning:pill>
                </div>
                <div aura:id="lookupField" class="slds-show">
                    <span class="slds-icon_container  slds-combobox__input-entity-icon" title="record">
                        <lightning:icon class="slds-icon slds-icon slds-icon_small slds-icon-text-default" iconName="{!v.IconName}" size="x-small" alternativeText="icon"/>
                        <span class="slds-assistive-text"></span>
                    </span>
                    <ui:inputText click="{!c.onfocus}" updateOn="keyup" keyup="{!c.keyPressController}" class="slds-lookup__search-input slds-input leftPaddingClass" value="{!v.SearchKeyWord}" placeholder="search.."/>
                </div>   
            </div>
        </div>
        <!--This part is for Display typehead lookup result List-->  
        <ul style="min-height:40px;margin-top:0px !important" class="slds-listbox slds-listbox_vertical slds-dropdown slds-dropdown_fluid slds-lookup__menu slds" role="listbox">
            <lightning:spinner class="slds-hide" variant="brand" size="small" aura:id="mySpinner"/>
            <center> {!v.Message}</center>
            <aura:iteration items="{!v.listOfSearchRecords}" var="singleRec">
                <c:customLookupResult oRecord="{!singleRec}" IconName="{!v.IconName}"/>
            </aura:iteration>
        </ul>
    </div>
</aura:component>
JS Controller [customLookupController.js]
({
   onfocus : function(component,event,helper){
       $A.util.addClass(component.find("mySpinner"), "slds-show");
        var forOpen = component.find("searchRes");
            $A.util.addClass(forOpen, 'slds-is-open');
            $A.util.removeClass(forOpen, 'slds-is-close');
        // Get Default 5 Records order by createdDate DESC  
         var getInputkeyWord = '';
         helper.searchHelper(component,event,getInputkeyWord);
    },
    onblur : function(component,event,helper){       
        component.set("v.listOfSearchRecords", null );
        var forclose = component.find("searchRes");
        $A.util.addClass(forclose, 'slds-is-close');
        $A.util.removeClass(forclose, 'slds-is-open');
    },
    keyPressController : function(component, event, helper) {
       // get the search Input keyword   
         var getInputkeyWord = component.get("v.SearchKeyWord");
       // check if getInputKeyWord size id more then 0 then open the lookup result List and 
       // call the helper 
       // else close the lookup result List part.   
        if( getInputkeyWord.length > 0 ){
             var forOpen = component.find("searchRes");
               $A.util.addClass(forOpen, 'slds-is-open');
               $A.util.removeClass(forOpen, 'slds-is-close');
            helper.searchHelper(component,event,getInputkeyWord);
        }
        else{  
             component.set("v.listOfSearchRecords", null ); 
             var forclose = component.find("searchRes");
               $A.util.addClass(forclose, 'slds-is-close');
               $A.util.removeClass(forclose, 'slds-is-open');
          }
	},
    
  // function for clear the Record Selaction 
    clear :function(component,event,heplper){
         var pillTarget = component.find("lookup-pill");
         var lookUpTarget = component.find("lookupField"); 
        
         $A.util.addClass(pillTarget, 'slds-hide');
         $A.util.removeClass(pillTarget, 'slds-show');
        
         $A.util.addClass(lookUpTarget, 'slds-show');
         $A.util.removeClass(lookUpTarget, 'slds-hide');
      
         component.set("v.SearchKeyWord",null);
         component.set("v.listOfSearchRecords", null );
         component.set("v.selectedRecord", {} );   
    },
    
  // This function call when the end User Select any record from the result list.   
    handleComponentEvent : function(component, event, helper) {
    // get the selected Account record from the COMPONETN event 	 
       var selectedAccountGetFromEvent = event.getParam("recordByEvent");
	   component.set("v.selectedRecord" , selectedAccountGetFromEvent); 
       
        var forclose = component.find("lookup-pill");
           $A.util.addClass(forclose, 'slds-show');
           $A.util.removeClass(forclose, 'slds-hide');
  
        var forclose = component.find("searchRes");
           $A.util.addClass(forclose, 'slds-is-close');
           $A.util.removeClass(forclose, 'slds-is-open');
        
        var lookUpTarget = component.find("lookupField");
            $A.util.addClass(lookUpTarget, 'slds-hide');
            $A.util.removeClass(lookUpTarget, 'slds-show');  
      
	},
})
JS Helper [customLookupHelper.js]
({
	searchHelper : function(component,event,getInputkeyWord) {
	  // call the apex class method 
     var action = component.get("c.fetchLookUpValues");
      // set param to method  
        action.setParams({
            'searchKeyWord': getInputkeyWord,
            'ObjectName' : component.get("v.objectAPIName")
          });
      // set a callBack    
        action.setCallback(this, function(response) {
          $A.util.removeClass(component.find("mySpinner"), "slds-show");
            var state = response.getState();
            if (state === "SUCCESS") {
                var storeResponse = response.getReturnValue();
              // if storeResponse size is equal 0 ,display No Result Found... message on screen.                }
                if (storeResponse.length == 0) {
                    component.set("v.Message", 'No Result Found...');
                } else {
                    component.set("v.Message", '');
                }
                // set searchResult list with return value from server.
                component.set("v.listOfSearchRecords", storeResponse);
            }
 
        });
      // enqueue the Action  
        $A.enqueueAction(action);
    
	},
})
Style Tab Code  [customLookup.CSS]
.THIS .leftPaddingClass {
    padding-left: 2rem;
}
 
.THIS .pillSize{
 width:100%;
}
TestApp.app
<aura:application extends="force:slds">
  <!-- Create attribute to store lookup value as a sObject--> 
  <aura:attribute name="selectedLookUpRecord" type="sObject" default="{}"/>
 
  <c:customLookup objectAPIName="account" IconName="standard:account" selectedRecord="{!v.selectedLookUpRecord}" label="Account Name"/>
 <!-- here c: is org. namespace prefix-->
</aura:application>
This is a dynamic Re-Usable Lightning Component you have need to pass the objectAPIName , IconNameselected Recordand Field Label Name Attribute when use this Custom Lookup component.

How to Use –  Example Custom Lookup Component

Now we are create a simple and small Lightning Component to create Contact Record Using custom Account Lookup and Name field.

Apex Controller 
public class contactSaveCtrl {
 @AuraEnabled 
    public static void saveContact(Contact con){
        insert con;
    }   
}
Lightning Component 
<aura:component controller="contactSaveCtrl" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
    <aura:attribute name="selectedLookUpRecord" type="sObject" default="{}"/>
    <aura:attribute name="objContact" type="contact" default="{'sobjectType':'contact'}"/>
  
  <div class="slds-m-around_large">
      <ui:inputText class="slds-input" value="{!v.objContact.LastName}" label="Last Name"/>
 
      <c:customLookup objectAPIName="account" IconName="standard:account" label="Account Name" selectedRecord="{!v.selectedLookUpRecord}"/>
      
<br/> 
      
    <button class="slds-utton slds-button_brand" onclick="{!c.saveContactRecord}">Save Contact</button>    
  </div>       
</aura:component>
JavaScript Controller 
({
	saveContactRecord : function(component, event, helper) {
        var conObj = component.get("v.objContact");
           //set the default accountId is null 
           conObj.AccountId = null ; 
       // check if selectedLookupRecord is not equal to undefined then set the accountId from 
       // selected Lookup Object to Contact Object before passing this to Server side method
        if(component.get("v.selectedLookUpRecord").Id != undefined){
          conObj.AccountId = component.get("v.selectedLookUpRecord").Id;
        } 
        
       //call apex class method
      var action = component.get('c.saveContact');
        action.setParams({
            'con': conObj
        })
      action.setCallback(this, function(response) {
        //store state of response
        var state = response.getState();
        if (state === "SUCCESS") {
         alert('Record Created');
        }
      });
      $A.enqueueAction(action);
        
       
	}
})
User-added image

Hope this helps.

Kindly mark this as solved if the reply was helpful so that it gets removed from the unanswered queue which results in helping others who are encountering a similar issue.

Thanks,
Nagendra









 
SFDC coderSFDC coder
Hi Nagendra,

 i have this code working but what m looking for is how to display dynamic columns. in the above example there is one static field i.e queried eg: name. i want to display eg: name,location,address in one component and name,email,phone in another component inside the lookup pop up. how can i achieve this?
Bhargav SuryaprakashBhargav Suryaprakash
Hi SFDC coder,

For this, you can pass an additional String parameter from customLookup.cmp to customLookupResult.cmp to capture the different components and manage what to display based on the passed value using aura:if.

For example, if you are calling the component for Account and Contact, have a separate String attribute that passess 'account' or 'contact' based on what it is for to the customLookupResult.cmp, and within that, for Account, you can display address, location, etc but for Contact, you can display name, email and phone.

Hope this helps.

Bhargav
Lee Anne GLee Anne G
Nagendra, this was an amazing and very useful example. Thank you SO much!
SF fanSF fan
Nagendra, thank you very much for the example! How do I move from the lookup to the results without a mouse, only by clickng the down key and enter to slect a result? 
Umang SinghalUmang Singhal
You can check sample code here: https://umangsinghal.wordpress.com/2019/08/26/custom-lookup-lightning-component/
Hariom Chaudhary 1Hariom Chaudhary 1
Can anyone please explain this code, i mean what is the flow of this ?
saileela podurusaileela poduru
Hii Nagendra,
i want to create a dynamic form and it is reusable that means if the object is account then the form must be displayed with account obj fields and if the object is contact then the form must be displayed with contact obj fields and the code must be in aura
please help me to write this code
Thank you
Javier Chaos 5Javier Chaos 5
That code above is from another post (https://developer.salesforce.com/forums/?id=9060G0000005V1zQAE).

If didn't work for my purposes as I had similar requirments as the original post plus others, so ended up doing my own.

Couple of extra things: disable state, default loaded record if you know the recordId, flexible search using multiple fields and flexible field selection for search results, show recent records, create and relate, etc... The closest to the native component and functionality I was able to get.

Code is available on github (https://github.com/Chaos-Tech-Corp/Input-Field-Lookup).