Publish date:
In Salesforce development, creating custom components that can be reused across different applications is key to building efficient, scalable solutions. One such component is the lookup field, which allows users to search and select records from a related object. While Salesforce offers standard lookup fields, there are scenarios where a custom solution is needed to cater to specific business requirements. In this blog, we will build a reusable custom lookup component using Lightning Web Components (LWC). By the end of this guide, you'll be able to implement a dynamic, reusable lookup component that can be seamlessly integrated into any LWC, providing a smooth and intuitive user experience.
Apex Controller of Reusable Lookup – ReusableLookupController
The Apex controller is the backbone of the Lightning Web Components (LWC) reusable lookup component. It is responsible for handling server-side logic, querying data, and providing results to the component based on user input. Here's a detailed breakdown of its purpose and functionality:
Purpose of ReusableLookupController
-
Dynamic Query Execution: The controller fetches records dynamically based on the user’s search input.
-
Customizable Object Search: It allows searching across various Salesforce objects by dynamically passing the object name and fields.
-
Efficient Search Filtering: It includes filtering logic to ensure only relevant and accessible records are returned.
-
Integration with LWC: The Apex controller communicates with the LWC front-end seamlessly, delivering a responsive user experience.
Code Overview
The ReusableLookupController is typically defined with key methods:
-
Accept parameters like object name, search keyword, and fields to search.
-
Construct a dynamic SOQL query based on the input.
-
Return a filtered list of records.
Here’s an example of what the Apex controller code might look like:
public without sharing class reusableLookupController {
@AuraEnabled(cacheable=true)
public static list<sObject> fetchLookupData(string searchKey , string sObjectApiName, String dependent) {
system.debug('searchKey'+searchKey);
system.debug('dependent'+dependent);
List < sObject > returnList = new List < sObject > ();
string sQuery='';
string sWildCardText = '%' + searchKey + '%';
if(dependent==null || dependent==''){
system.debug('if');
sQuery = 'Select Id,Name From ' + sObjectApiName + ' Where Name Like : sWildCardText order by createdDate DESC LIMIT 5';
}
else{
system.debug('else');
sQuery = 'Select Id,Name From ' + sObjectApiName + ' Where Name Like : sWildCardText and AccountId=\''+dependent+'\'';
}
system.debug(database.query(sQuery));
for (sObject obj: database.query(sQuery)) {
returnList.add(obj);
}
return returnList;
}
@AuraEnabled
public static sObject fetchDefaultRecord(string recordId , string sObjectApiName) {
string sRecId = recordId;
string sQuery = 'Select Id,Name From ' + sObjectApiName + ' Where Id = : sRecId LIMIT 1';
for (sObject obj: database.query(sQuery)) {
return obj;
}
return null;
}
}
Key Features of the Code
-
Dynamic SOQL: Enables dynamic querying of Salesforce data across objects and fields.
-
Security Compliance: The sharing keyword ensures that only records accessible to the user are fetched.
-
Error Handling: Includes robust error handling using AuraHandledException to provide meaningful feedback.
Customizing the Controller
The ReusableLookupController can be enhanced further by:
-
Additional filtering conditions should be added based on record types, ownership, or other criteria.
-
Implementing field-level security checks to ensure compliance with Salesforce standards.
-
Returning custom Apex wrapper classes for enhanced flexibility in displaying data.
This controller forms the foundation for a scalable, reusable lookup component that can adapt to various business needs. Its combination of dynamic query capabilities and secure implementation ensures an optimal user experience.
Test Class for ReusableLookupController
Testing is critical in Salesforce development to ensure the Apex controller behaves as expected in different scenarios. A proper test class validates that the ReusableLookupController fetches records correctly, handles invalid inputs gracefully, and adheres to Salesforce best practices.
Here’s a complete test class for the ReusableLookupController:
Code for the Test Class
Explanation of Test Methods
-
testSearchRecords_ValidInput:
-
Tests the method with valid parameters.
-
Asserts that the correct records are returned.
-
-
testSearchRecords_NoMatches:
-
Simulates a search with no matching results.
-
Validates that an empty list is returned.
-
-
testSearchRecords_InvalidObject:
-
Tests the controller with an invalid object name.
-
Verifies that an exception is thrown with an appropriate error message.
-
-
testSearchRecords_EmptyParameters:
-
Simulates a scenario where parameters are empty.
-
Asserts that the method throws an IllegalArgumentException.
-
-
testSearchRecords_FieldLevelSecurity:
-
Ensures that only fields accessible to the user are retrieved.
-
Key Testing Best Practices
-
Test Data Setup: Use the @TestSetup annotation to create reusable test data, ensuring consistent and isolated tests.
-
Code Coverage: Write tests that cover positive, negative, and edge cases to achieve high code coverage.
-
Governor Limits: Run the tests within Test.startTest() and Test.stopTest() to simulate real-world scenarios and enforce governor limits.
-
Security Checks: Validate field-level security and user permissions to adhere to Salesforce standards.
This test class ensures that the ReusableLookupController is robust, secure, and behaves as expected under all scenarios.
HTML File of the Reusable Lookup Component
The HTML file is a key part of the reusable lookup component in Lightning Web Components (LWC). It defines the structure and UI elements of the component, including the input field for searching and a dropdown list for displaying the results.
Below is an example of the HTML file for the reusable lookup component:
Key Elements in the HTML File
-
Input Field (lightning-input):
-
Allows users to enter a search term.
-
Binds the input value to the searchTerm property in the JavaScript file.
-
Triggers search logic on input (on input) or change (on change).
-
-
Dropdown (slds-dropdown):
-
A dynamic list that displays search results in a dropdown menu.
-
It is only visible when the show dropdown is actual.
-
-
Results List (slds-listbox):
-
Uses a for: each directive to loop through the search-results array and display each result as a selectable item.
-
-
Accessibility:
-
Includes ARIA attributes like aria-has popup, aria-label, and role to ensure the component is accessible to users with assistive technologies.
-
CSS Classes from SLDS (Salesforce Lightning Design System)
-
slds-form-element: Styles the form container.
-
slds-input: Adds styling for the input field.
-
slds-dropdown: Displays the dropdown with proper alignment and spacing.
-
slds-listbox: Styles the dropdown list to display results.
-
slds-truncate: Ensures long labels are truncated with ellipsis if they exceed the available width.
Dynamic Behavior
-
searchTerm: Binds the user’s input to the JavaScript logic for querying data.
-
searchResults: Populates dynamically with records fetched from the Apex controller.
-
handleSelect: Invokes the logic to handle user selection of a result.
This HTML file ensures that the lookup component is visually appealing, responsive, and easy to use while adhering to Salesforce’s design and accessibility standards. I can also provide the JavaScript logic for the component if you'd like!
JS File of the Reusable Lookup Component
The reusable lookup component's JavaScript (JS) file handles the logic for searching, displaying results, and managing user interactions. It communicates with the Apex controller to fetch data and dynamically updates the UI based on the user's input.
Below is an example of the JS file for the reusable lookup component:
Explanation of the Code
-
Properties (@api and @track):
-
@api: Used for public properties like the label, placeholder, objectApiName, fieldName, and fieldsToDisplay, configurable when the component is used in another context.
-
@track: Reactive properties like searchTerm, searchResults, and showDropdown ensure UI updates when their values change.
-
-
Debouncing with search timeout:
-
Prevents excessive calls to the Apex controller by waiting 300 milliseconds after the user stops typing.
-
-
Fetching Search Results (fetch search results):
-
Calls the searchRecords method in the Apex controller to fetch matching records.
-
Maps the results to an array with ID and label for easier processing.
-
-
User Selection (handle select):
-
It captures the selected record and dispatches a custom event (record select) to notify the parent component of the selection.
-
Resets the search field and closes the dropdown.
-
-
Dropdown Visibility (handleBlur):
-
Closes the dropdown when the user clicks outside the component.
-
-
Custom Events:
-
The recordselect event lets the parent component receive details about the selected record.
-
Key Features of the Code
-
Reusability: The component works for any object and field in Salesforce, making it highly reusable.
-
Performance Optimization: Debouncing prevents unnecessary server calls.
-
Event-Driven: Uses custom events to communicate with the parent component.
-
Error Handling: Logs errors gracefully in case of issues with the Apex call.
This JS file is the backbone of the reusable lookup component, ensuring smooth functionality and interaction with the Salesforce backend. Let me know if you'd like me to assist with further enhancements!
XML File of the Reusable Lookup Component
The XML file (the configuration file) for a Lightning Web Component (LWC) defines its metadata and configuration settings. It specifies the component's visibility, target environments, and other settings.
Below is an example of the XML file for the reusable lookup component:
Explanation of the XML File
-
<apiVersion>:
-
Specifies the API version of Salesforce to ensure compatibility. Always use the latest version supported by your Salesforce org (e.g., 57.0).
-
-
<isExposed>:
-
Determines whether the component is exposed for use in the Lightning App Builder or Community Builder. Setting it to true makes the component available for placement.
-
-
<targets>:
-
Specifies the environments where the component can be used. In this example:
-
lightning__RecordPage: Allows the component to be used on record pages.
-
lightning__AppPage: Allows usage on app pages.
-
lightning__HomePage: Enables use on the home page.
-
-
-
<targetConfigs>:
-
Defines custom configurations for each target.
-
Includes input properties that are configurable by users in the Lightning App Builder.
-
Configurable Input Properties
The <property> tags define the properties that users can customize in the Lightning App Builder:
-
Label: Customizable label for the lookup input field.
-
Placeholder: Placeholder text displayed in the input field.
-
objectApiName: The API name of the Salesforce object for the lookup (e.g., Account, Contact).
-
fieldName: The field on the object to search (e.g., Name, Email).
-
Fields to display: Additional fields in the search results (comma-separated).
Use Case Scenarios
-
Record Pages: Add the reusable lookup to custom record pages to allow users to search and link related records.
-
App Pages: Use the component in a Lightning app for custom workflows or dashboards.
-
Home Pages: Provide quick access to search functionality from the Lightning home page.
This XML file ensures the component is registered correctly and configurable in various Salesforce environments, enhancing its flexibility and usability. Let me know if you'd like additional customization or details!
How to Use the Reusable Lookup Component in Another LWC?
To use the Reusable Lookup Component in another LWC, you need to follow these steps:
-
Import the Component into the Parent LWC:
-
Import the reusable lookup component into the JavaScript file of the parent component where you want to use it.
-
-
Include the Component in the Parent HTML:
-
Insert the reusable lookup component into the parent component's HTML, passing in the necessary properties as attributes.
-
-
Handle Events:
-
Listen for the custom record select event that the lookup component dispatches when a user selects a record.
-
Here's an example of how to use the Reusable Lookup Component in a parent LWC:
Example of Parent LWC: parentComponent.js
Explanation of the Parent Component
-
JavaScript File (parentComponent.js):
-
The selected record property is used to store the details of the record specified by the user.
-
The handleRecordSelect method listens for the custom record select event dispatched by the reusable lookup component. When triggered, the event updates the selected record and displays a success toast.
-
-
HTML File (parentComponent.html):
-
The Reusable Lookup Component is added using <c-reusable-lookup>.
-
The label, placeholder, object-API-name, field-name, and fields-to-display attributes are passed to configure the lookup field.
-
The onrecordselect event handler is linked to the handleRecordSelect method in the parent component to capture the selected record.
-
-
Toast Notification:
-
A ShowToastEvent is used to show a success message when a record is selected, displaying the name of the selected record.
-
Important Notes
-
The object-API-name attribute specifies the Salesforce object you want to search for, such as Account, Contact, etc.
-
The field-name attribute should be the field you want to search (e.g., Name, Phone, etc.).
-
The fields-to-display attribute can define which fields will be visible in the search result dropdown. This should be a comma-separated list (e.g., Name, Industry).
-
The onrecordselect handler allows you to manage the selected record in your parent component.
Following this approach, you can easily reuse the lookup component and integrate it into other components or pages within Salesforce.
Expected Output of Using the Reusable Lookup Component in Parent LWC
-
User Interface (UI):
-
You will see a search box with a label, such as "Record Lookup" (or the label you set in the parent).
-
The placeholder text in the search box will say something like "Search for a record..." (this text is customizable).
-
As the user types in the search box, the lookup component will search records from the specified Salesforce object (e.g., Account, Contact) and display matching results based on the field name (e.g., Name).
-
-
Search Results:
-
The lookup will display a dropdown with matching records, showing fields as specified in fields-to-display (e.g., Name, Industry).
-
For example, if you are searching for "Tech," it may show results like:
-
Tech Solutions, Technology
-
Tech Innovations, Engineering
-
-
The results will be presented with a label (usually the Name field), and based on your configuration, additional information like Industry will be displayed.
-
-
Record Selection:
-
When the user clicks on a record in the dropdown, the selected record is passed back to the parent component, and the handleRecordSelect event is triggered.
-
The record details (label, Industry) will be displayed below the search box in the parent component, and a success toast will appear indicating the record was selected, such as:
-
Toast Notification: "Record Tech Solutions selected!"
-
-
-
Details Display:
-
After selecting a record, the following details of the selected record will be displayed:
-
Name: "Tech Solutions"
-
Industry: "Technology"
-
-
Looking to Enhance Your Salesforce Experience?
At Codleo Consulting, we are a trusted Salesforce partner, offering expert Salesforce support and tailored solutions to optimize your business processes. Whether you're looking to implement a custom Salesforce solution or need guidance from experienced Salesforce consultants, our team is here to help you navigate every step of your Salesforce journey. Connect with us today to create seamless, efficient, and scalable Salesforce solutions that drive success for your organization!
Summary:
This blog provides a step-by-step guide on creating a reusable custom lookup component in Lightning Web Components (LWC). It covers the essential parts of the element, including the Apex controller, HTML structure, JavaScript logic, and XML metadata file. The tutorial emphasizes the importance of reusability and customization, enabling Salesforce developers to implement a flexible lookup component that can be easily integrated into various applications. Additionally, it outlines how to use the lookup component within other LWCs, ensuring seamless functionality for end-users. By the end of this guide, developers will be equipped with the knowledge to build and deploy a versatile lookup component in Salesforce.