HTML:
<template>
<lightning-card title = “{Title}”>
<lightning-button label=”New” slot=”actions” onclick = {createNew}></lightning-button>
<lightning-input type = “search” onblur = {handleKeyChange} class = “slds-m-bottom_small” label = “Search” >
</lightning-input>
<template if:true = {listRecs}>
<div style=”height: 300px;”>
<lightning-datatable key-field=”Id”
data={listRecs}
columns={columns}
hide-checkbox-column=”true”
show-row-number-column=”true”
default-sort-direction={defaultSortDirection}
sorted-direction={sortDirection}
sorted-by={sortedBy}
onsort={onHandleSort}
onrowaction={handleRowAction}>
</lightning-datatable>
</div>
</template>
<template if:true = {error}>
{error}>
</template>
</lightning-card>
</template>
JavaScript:
import { api, LightningElement, track, wire } from ‘lwc’;
import fetchRecs from ‘@salesforce/apex/CustomListViewController.fetchRecs’;
import { NavigationMixin } from ‘lightning/navigation’;
export default class customListView extends NavigationMixin( LightningElement ) {
@track listRecs;
@track initialListRecs;
@track error;
@track columns;
@api AccountId;
@api RelatedObject;
@api Fields;
@api RelatedField;
@api TableColumns;
@api Title;
sortedBy;
defaultSortDirection = ‘asc’;
sortDirection = ‘asc’;
connectedCallback() {
console.log( ‘Columns are ‘ + this.TableColumns );
this.columns = JSON.parse( this.TableColumns.replace( /([a-zA-Z0-9]+?):/g, ‘”$1″:’ ).replace( /’/g, ‘”‘ ) );
console.log( ‘Columns are ‘ + this.columns );
}
get vals() {
return this.RelatedObject + ‘-‘ + this.Fields + ‘-‘ +
this.RelatedField + ‘-‘ + this.AccountId;
}
@wire(fetchRecs, { listValues: ‘$vals’ })
wiredRecs( { error, data } ) {
if ( data ) {
console.log( ‘Records are ‘ + JSON.stringify( data ) );
this.listRecs = data;
this.initialListRecs = data;
} else if ( error ) {
this.listRecs = null;
this.initialListRecs = null;
this.error = error;
}
}
handleKeyChange( event ) {
const searchKey = event.target.value.toLowerCase();
console.log( ‘Search Key is ‘ + searchKey );
if ( searchKey ) {
this.listRecs = this.initialListRecs;
if ( this.listRecs ) {
let recs = [];
for ( let rec of this.listRecs ) {
console.log( ‘Rec is ‘ + JSON.stringify( rec ) );
let valuesArray = Object.values( rec );
console.log( ‘valuesArray is ‘ + valuesArray );
for ( let val of valuesArray ) {
if ( val.toLowerCase().includes( searchKey ) ) {
recs.push( rec );
break;
}
}
}
console.log( ‘Recs are ‘ + JSON.stringify( recs ) );
this.listRecs = recs;
}
} else {
this.listRecs = this.initialListRecs;
}
}
onHandleSort( event ) {
const { fieldName: sortedBy, sortDirection } = event.detail;
const cloneData = […this.listRecs];
cloneData.sort( this.sortBy( sortedBy, sortDirection === ‘asc’ ? 1 : -1 ) );
this.listRecs = cloneData;
this.sortDirection = sortDirection;
this.sortedBy = sortedBy;
}
sortBy( field, reverse, primer ) {
const key = primer
? function( x ) {
return primer(x[field]);
}
: function( x ) {
return x[field];
};
return function( a, b ) {
a = key(a);
b = key(b);
return reverse * ( ( a > b ) – ( b > a ) );
};
}
handleRowAction( event ) {
const actionName = event.detail.action.name;
const row = event.detail.row;
switch ( actionName ) {
case ‘view’:
this[NavigationMixin.GenerateUrl]({
type: ‘standard__recordPage’,
attributes: {
recordId: row.Id,
actionName: ‘view’,
},
}).then(url => {
window.open(url);
});
break;
case ‘edit’:
this[NavigationMixin.Navigate]({
type: ‘standard__recordPage’,
attributes: {
recordId: row.Id,
objectApiName: this.RelatedObject,
actionName: ‘edit’
}
});
break;
default:
}
}
createNew() {
this[NavigationMixin.Navigate]({
type: ‘standard__objectPage’,
attributes: {
objectApiName: this.RelatedObject,
actionName: ‘new’
}
});
}
}
meta.xml:
<?xml version=”1.0″ encoding=”UTF-8″?>
<LightningComponentBundle xmlns=”http://soap.sforce.com/2006/04/metadata”>
<apiVersion>49.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
<targetConfigs>
<targetConfig targets=”lightningCommunity__Default”>
<property name=”AccountId” type=”String”/>
<property name=”RelatedObject” type=”String”/>
<property name=”RelatedField” type=”String”/>
<property name=”Fields” type=”String”/>
<property name=”TableColumns” type=”String”/>
<property name=”Title” type=”String”/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Apex Class:
public with sharing class CustomListViewController {
@AuraEnabled( cacheable = true )
public static List < sObject > fetchRecs( String listValues ) {
system.debug( ‘values are ‘ + listValues );
List < String > strList = listValues.split( ‘-‘ );
system.debug( ‘values are ‘ + strList );
String strObject = strList.get( 0 );
String strFields = strList.get( 1 );
String strRelatedField = strList.get( 2 );
String strAccountId;
if ( strList.size() == 4)
strAccountId = strList.get( 3 );
List < sObject > listRecs = new List < sObject >();
String strSOQL = ‘SELECT Id, ‘ + strFields + ‘ FROM ‘ + strObject;
if ( String.isNotBlank( strAccountId ) )
strSOQL += ‘ WHERE ‘ + strRelatedField+ ‘ = ” + strAccountId + ”’;
strSOQL += ‘ LIMIT 25’;
system.debug( ‘SOQL is ‘ + strSOQL );
listRecs = Database.query( strSOQL );
return listRecs;
}
}
TableColumns
[{label:’First Name’,fieldName:’FirstName’,sortable:true},{label:’Last Name’,fieldName:’LastName’},{ label:’Email’,fieldName: ‘Email’},{type:’action’,typeAttributes:{rowActions:[{label:’View’,name:’view’},{label:’Edit’,name:’edit’}]}}]
TableColumns
[{label:’Subject’,fieldName:’Subject’ },{label:’Origin’,fieldName: ‘Origin’,sortable: true},{ label:’Reason’,fieldName:’Reason’},{label:’Status’, fieldName:’Status’},{type:’action’,typeAttributes:{rowActions:[{label:’View’,name:’view’},{label:’Edit’,name:’edit’}]}}]