Creating a Custom List View in Salesforce Using LWC and Apex
In this blog post, we’ll guide you through the process of creating a custom list view in Salesforce using Lightning Web Components (LWC) and Apex. This will enable you to fetch, display, and print Task records based on specific filters. We’ll cover the step-by-step development of the Apex controller, LWC component, and the creation of a list layout button to enhance your Salesforce interface.
Thank you for reading this post, don't forget to subscribe!Prerequisites
- Basic understanding of Salesforce development.
- Familiarity with Apex and Lightning Web Components.
- Access to a Salesforce org with appropriate permissions.
Step 1: Create a Visualforce Page
Start by creating a Visualforce page that connects to the LWC, named ListviewPage
.
htmlCopy code<apex:page standardController="Task" recordSetVar="tasks" extensions="CustomListViewInLwcCtrl">
<apex:includeLightning />
<style>
#lightning {
height: 100vh;
}
@media print {
#lightning {
height: auto;
overflow: visible;
}
.print-section {
height: auto;
overflow: visible;
}
}
</style>
<div id="lightning"></div>
<script>
console.log('work6');
var filterId = '{!filterId}';
console.log('Filter ID:', filterId);
$Lightning.use(
"c:ExampleLWCApp",
function() {
$Lightning.createComponent(
"c:listviewpage",
{
'filterId': filterId
},
"lightning"
);
}
);
</script>
</apex:page>
Step 2: Create an Aura Component
htmlCopy code<aura:application extends="ltng:outApp">
<aura:dependency resource="listviewpage" />
</aura:application>
Step 3: Create an Apex Controller
Next, you’ll need an Apex controller to manage the fetching of list views and their associated records.
apexCopy codepublic with sharing class CustomListViewInLwcCtrl {
private String filterId;
public CustomListViewInLwcCtrl(ApexPages.StandardSetController controller) {
filterId = controller.getFilterId();
System.debug('FilterId--> ' + filterId);
}
public String getFilterId() {
return filterId;
}
@AuraEnabled(cacheable = true)
public static List<ListView> fetchTaskListView(String objectApiName) {
try {
return [
SELECT Id, Name, DeveloperName
FROM ListView
WHERE SObjectType = :objectApiName
ORDER BY DeveloperName ASC
];
} catch (Exception e) {
System.debug('Error fetching list views: ' + e.getMessage());
return new List<ListView>();
}
}
@AuraEnabled(cacheable = true)
public static List<sObject> getTaskListviewRecord(String objectName, String listViewId, String limitsize, String offsize) {
// Logic to fetch Task records
}
@AuraEnabled(cacheable = true)
public static List<Map<String, String>> getTaskListviewLabel(String objectName, String listViewId) {
// Logic to fetch Task record labels
}
}
Step 4: Create a Lightning Web Component
Create the LWC listviewPage
that will interact with the Apex controller.
HTML Template
htmlCopy code<template>
<div class="slds-grid slds-wrap" style="width: 280px;">
<div class="slds-m-around_medium">
<lightning-combobox
name="listViewSelect"
label="Select List View"
value={selectedListView}
placeholder="Select a List View"
options={listViewOptions}
onchange={handleListViewChange}>
</lightning-combobox>
</div>
</div>
<br>
<div class="slds-grid slds-wrap">
<div class="slds-col slds-size_1-of-4"></div>
<div class="slds-col slds-size_3-of-4 slds-text-align_right">
<lightning-button variant="brand" label="Print" onclick={handlePrint}></lightning-button>
</div>
</div>
<br>
<div if:true={isLoading}>
<lightning-spinner alternative-text="Loading"></lightning-spinner>
</div>
<template if:false={isLoading}>
<div class="print-section">
<template if:true={records.length}>
<lightning-datatable key-field="Id" data={records} columns={columns} hide-checkbox-column></lightning-datatable>
<div class="slds-m-top_medium slds-text-align_center">
<lightning-button-group>
<lightning-button class="previous" label="Previous" onclick={handlePrevious} disabled={disablePrevious}></lightning-button>
<lightning-button class="next" label="Next" onclick={handleNext} disabled={disableNext}></lightning-button>
</lightning-button-group>
</div>
</template>
<template if:false={records.length}>
<div class="slds-text-align_center">
No records to display
</div>
</template>
</div>
</template>
</template>
JavaScript Controller
javascriptCopy codeimport { LightningElement, track, wire, api } from 'lwc';
import fetchListView from '@salesforce/apex/CustomListViewInLwcCtrl.fetchTaskListView';
import getTaskListviewRecord from '@salesforce/apex/CustomListViewInLwcCtrl.getTaskListviewRecord';
import getTaskListviewLabel from '@salesforce/apex/CustomListViewInLwcCtrl.getTaskListviewLabel';
const PAGE_SIZE = 100;
export default class ListviewPage extends LightningElement {
@api filterId;
@track listViewOptions = [];
@track selectedListView = '';
@track records = [];
@track columns = [];
@track isLoading = true;
@track limitsize = PAGE_SIZE;
@track offset = 0;
connectedCallback() {
console.log('Filter ID:', this.filterId);
}
@wire(fetchListView, { objectApiName: 'Task' })
fetchListViewHandler({ data, error }) {
if (data) {
this.listViewOptions = data.map(listView => ({
label: listView.Name,
value: listView.Id
}));
this.selectedListView = this.filterId || this.listViewOptions[0].value;
this.fetchRecords();
} else if (error) {
console.error('Error fetching list views:', error);
}
}
fetchRecords() {
this.isLoading = true;
getTaskListviewRecord({
objectName: 'Task',
listViewId: this.selectedListView,
limitsize: this.limitsize.toString(),
offsize: this.offset.toString()
})
.then(result => {
console.log(`${result.length} records`, result);
this.records = this.formatRecords(result);
this.fetchLabels();
})
.catch(error => {
console.error('Error fetching records:', error);
this.records = [];
this.isLoading = false;
});
}
formatRecords(records) {
return records.map((record, index) => ({
...record,
Count: this.offset + index + 1,
// Additional field mappings
}));
}
fetchLabels() {
getTaskListviewLabel({
objectName: 'Task',
listViewId: this.selectedListView
})
.then(labels => {
this.columns = [
{ label: ' ', fieldName: 'Count', type: 'number' },
...labels.map(labelInfo => ({
label: labelInfo.label,
fieldName: labelInfo.fieldApiName,
type: 'text'
}))
];
this.isLoading = false;
})
.catch(error => {
console.error('Error fetching labels:', error);
this.isLoading = false;
});
}
handleListViewChange(event) {
this.selectedListView = event.detail.value;
this.offset = 0;
this.fetchRecords();
}
handlePrint() {
if (confirm('Are you sure you want to print?')) {
window.print();
}
}
handlePrevious() {
if (this.offset >= PAGE_SIZE) {
this.offset -= PAGE_SIZE;
this.fetchRecords();
}
}
handleNext() {
this.offset += PAGE_SIZE;
this.fetchRecords();
}
get disablePrevious() {
return this.offset === 0;
}
get disableNext() {
return this.records.length < PAGE_SIZE;
}
}
Step 5: Handle Remote Site Settings
To allow your Apex class to make callouts, add your Salesforce org’s URL to the Remote Site Settings:
- Navigate to Setup.
- Search for “Remote Site Settings” in the Quick Find box.
- Click “New Remote Site.”
- Fill in the required fields (e.g., Remote Site Name:
MyOrgSite
, Remote Site URL:https://myorg.my.salesforce.com
). - Save the settings.
Step 6: Create a List Layout Button
To create a button that opens your custom list view Visualforce page:
- Go to Salesforce Setup.
- Navigate to Object Manager and select the
Task
object. - Go to Buttons, Links, and Actions.
- Click “New Button or Link.”
- Choose the appropriate settings:
- Label: Custom List View
- Name: Custom_List_View
- Display Type: Detail Page Button
- Behavior: Display in a new window
- Content Source: URL
- Use the following URL as the content source:
/apex/ListviewPage?filterId={!Task.FilterId}
Conclusion
This custom list view component in Salesforce allows for enhanced record handling, display, and printing, offering greater flexibility than the standard list views. By leveraging LWC and Apex, you can create a tailored experience for your users, improving their efficiency and overall satisfaction.
If this was tl;dr, contact Tectonic for assistance today.