September 24, 2020

Reusable Custom List View with dynamic datatable for Salesforce Community using LWC

Sample Code:

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;
          
    }  

}

Community Builder Configuration:
 
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'}]}}]

Output:
 


 

No comments:

Post a Comment