├── .forceignore ├── .gitattributes ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── README.md ├── config └── project-scratch-def.json ├── force-app └── main │ └── default │ ├── classes │ ├── LightningDataTableController.cls │ └── LightningDataTableController.cls-meta.xml │ └── lwc │ ├── .eslintrc.json │ ├── jsconfig.json │ └── lightningDataTable │ ├── lightningDataTable.html │ ├── lightningDataTable.js │ └── lightningDataTable.js-meta.xml ├── manifest └── package.xml └── sfdx-project.json /.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sfdx/ 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Dependency directories 16 | node_modules/ 17 | 18 | # Eslint cache 19 | .eslintcache 20 | 21 | # MacOS system files 22 | .DS_Store 23 | 24 | # Windows system files 25 | Thumbs.db 26 | ehthumbs.db 27 | [Dd]esktop.ini 28 | $RECYCLE.BIN/ -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running prettier 2 | # More information: https://prettier.io/docs/en/ignore.html 3 | # 4 | 5 | .sfdx -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "overrides": [ 4 | { 5 | "files": "**/lwc/**/*.html", 6 | "options": { "parser": "lwc" } 7 | }, 8 | { 9 | "files": "*.{cmp,page,component}", 10 | "options": { "parser": "html" } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "salesforce.salesforcedx-vscode", 4 | "redhat.vscode-xml", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Apex Replay Debugger", 9 | "type": "apex-replay", 10 | "request": "launch", 11 | "logFile": "${command:AskForLogFileName}", 12 | "stopOnEntry": true, 13 | "trace": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "salesforcedx-vscode-core.push-or-deploy-on-save.enabled": false, 3 | "search.exclude": { 4 | "**/node_modules": true, 5 | "**/bower_components": true, 6 | "**/.sfdx": true 7 | }, 8 | "eslint.nodePath": "c:\\Users\\Phill\\.vscode\\extensions\\salesforce.salesforcedx-vscode-lwc-46.11.0\\node_modules" 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Salesforce Lightning Web Component table that can be used in the Lightning App Builder or Community Builder and is driven off of a field set and object API name. 2 | 3 | # Types of Lists 4 | * List 5 | * a list of any records in the system 6 | * provide the Sobject API name and Field Set name 7 | * Related List 8 | * a list of any related records to a parent record 9 | * provide the Sobject API name, Field Set name, and Sobject Lookup Field API Name 10 | * Filtered List 11 | * a list of any records filted by a SOQL WHERE statement 12 | * provide the Sobject API name, Field Set name, and Additional Where Clause 13 | * Filtered Related List 14 | * a list of filtered related records to a parent record 15 | * Rendered if all attributes are filled out 16 | 17 | # Configure Components 18 | ## Drag Components onto a page 19 | This component works on app pages, record pages, home pages, and community pages. 20 | 21 | Here is a table breakdown of what lists work on what pages: 22 | 23 | | | App Pages | Record Pages | Home Pages | Community Pages | 24 | |:-:|:-:|:-:|:-:|:-:| 25 | | Lists | X | | X | X | 26 | | Related Lists | X | X | X | X | 27 | | Filtered Lists | X | X | X | X | 28 | | Filtered Related Lists | X | X | X | X | 29 | 30 | # Edit the attributes 31 | * Object API Name - The API name of the object where the layout was placed (Community Record Page only) 32 | * Field Set API Name - API name of the field set on the Object API Name 33 | * sObject Lookup Field API Name - API name of the sObject field used in a lookup or master-detail relationship 34 | * sObject API Name ==> sObject Lookup Field API Name 35 | * Contact ==> AccountId 36 | * Contact ==> AccountId 37 | * Opportunity ==> AccountId 38 | * (Additional) WHERE Clause in SOQL Query - optional filtering statement for WHERE clause in SOQL queries 39 | 40 | # Example Uses 41 | ![App Page Data Table](https://user-images.githubusercontent.com/20356405/63729244-92fc4c80-c85e-11e9-82da-30de152fce19.gif) 42 | ![Record Page Data Table](https://user-images.githubusercontent.com/20356405/63729278-a7404980-c85e-11e9-8ee2-e6268096829a.gif) 43 | -------------------------------------------------------------------------------- /config/project-scratch-def.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "Demo Company", 3 | "edition": "Developer", 4 | "features": [], 5 | "settings": { 6 | "orgPreferenceSettings": { 7 | "s1DesktopEnabled": true 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /force-app/main/default/classes/LightningDataTableController.cls: -------------------------------------------------------------------------------- 1 | public with sharing class LightningDataTableController { 2 | /* 3 | Created by Phill Drum 4 | Purpose: Create a lightning-datatable based on configuration inputs to create lists, related lists, filtered lists, and filtered related lists. 5 | Based off of http://sfdcmonkey.com/2018/01/05/lightning-datatable-base-component/ 6 | */ 7 | @AuraEnabled(cacheable=true) 8 | public static DataTableResponse getSobjectRecords(String sObjectName, String fieldSetName, String sObjectLookupIDField, String additionalWhereClause, String recordId){ 9 | 10 | //Get the fields from FieldSet 11 | Schema.SObjectType SObjectTypeObj = Schema.getGlobalDescribe().get(sObjectName); 12 | Schema.DescribeSObjectResult DescribeSObjectResultObj = SObjectTypeObj.getDescribe(); 13 | Schema.FieldSet fieldSetObj = DescribeSObjectResultObj.FieldSets.getMap().get(fieldSetName); 14 | 15 | //List to hold table headers 16 | List lstDataColumns = new List(); 17 | 18 | //Fields to be queried from fieldset 19 | List lstFieldsToQuery = new List(); 20 | 21 | //Final wrapper response to return to component 22 | DataTableResponse response = new DataTableResponse(); 23 | 24 | for( Schema.FieldSetMember eachFieldSetMember : fieldSetObj.getFields() ){ 25 | String dataType = String.valueOf(eachFieldSetMember.getType()).toLowerCase(); 26 | //This way we can set the type of a column 27 | //We do not get the exact type from schema object which matches to lightning-datatable component structure 28 | if(dataType == 'datetime'){ 29 | dataType = 'date'; 30 | } 31 | //Create a wrapper instance and store label, fieldname and type. 32 | DataTableColumns datacolumns = new DataTableColumns( String.valueOf(eachFieldSetMember.getLabel()) , 33 | String.valueOf(eachFieldSetMember.getFieldPath()), 34 | String.valueOf(eachFieldSetMember.getType()).toLowerCase() ); 35 | lstDataColumns.add(datacolumns); 36 | lstFieldsToQuery.add(String.valueOf(eachFieldSetMember.getFieldPath())); 37 | } 38 | 39 | //SOQL Queries for different lists: lists, related lists, filtered lists, and filtered related lists 40 | String query = ''; 41 | if(!lstDataColumns.isEmpty() && String.isEmpty(recordId) && String.isEmpty(additionalWhereClause) && String.isEmpty(sObjectLookupIDField)){ 42 | //List 43 | query = 'SELECT Id, ' + String.join(lstFieldsToQuery, ',') + 44 | ' FROM ' + sObjectName; 45 | System.debug(query); 46 | }else if (! lstDataColumns.isEmpty() && String.isEmpty(additionalWhereClause)){ 47 | //Related List 48 | query = 'SELECT Id, ' + String.join(lstFieldsToQuery, ',') + 49 | ' FROM ' + sObjectName + 50 | ' WHERE ' + sObjectLookupIDField + ' = \'' + recordId + '\''; 51 | } 52 | else if (! lstDataColumns.isEmpty() && String.isEmpty(recordId)){ 53 | //Filtered List 54 | query = 'SELECT Id, ' + String.join(lstFieldsToQuery, ',') + 55 | ' FROM ' + sObjectName + 56 | ' WHERE ' + additionalWhereClause; 57 | } 58 | else{ 59 | //Filtered Related List 60 | query = 'SELECT Id, ' + String.join(lstFieldsToQuery, ',') + 61 | ' FROM ' + sObjectName + 62 | ' WHERE ' + sObjectLookupIDField + '= \'' + recordId + '\''+ 63 | ' AND '+ additionalWhereClause; 64 | } 65 | response.dataTableData = Database.query(query); 66 | response.listColumns = lstDataColumns; 67 | return response; 68 | } 69 | 70 | //Wrapper class to hold Columns with headers 71 | public class DataTableColumns { 72 | @AuraEnabled 73 | public String label {get;set;} 74 | @AuraEnabled 75 | public String fieldName {get;set;} 76 | @AuraEnabled 77 | public String type {get;set;} 78 | 79 | //Create and set variables required by lightning-datatable (label, fieldname, and type) 80 | public DataTableColumns(String label, String fieldName, String type){ 81 | this.label = label; 82 | this.fieldName = fieldName; 83 | this.type = type; 84 | } 85 | } 86 | 87 | //Wrapper calss to hold response 88 | public class DataTableResponse { 89 | @AuraEnabled 90 | public List listColumns {get;set;} 91 | @AuraEnabled 92 | public List dataTableData {get;set;} 93 | 94 | public DataTableResponse(){ 95 | listColumns = new List(); 96 | dataTableData = new List(); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/LightningDataTableController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 46.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@salesforce/eslint-config-lwc/recommended"] 3 | } 4 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "baseUrl": ".", 5 | "paths": { 6 | "c/lightningDataTable": [ 7 | "lightningDataTable/lightningDataTable.js" 8 | ] 9 | } 10 | }, 11 | "include": [ 12 | "**/*", 13 | "../../../../.sfdx/typings/lwc/**/*.d.ts" 14 | ], 15 | "typeAcquisition": { 16 | "include": [ 17 | "jest" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/lightningDataTable/lightningDataTable.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/lightningDataTable/lightningDataTable.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, wire, track, api } from 'lwc'; 2 | import getSobjectRecords from '@salesforce/apex/LightningDataTableController.getSobjectRecords' 3 | 4 | export default class LightningDataTable extends LightningElement { 5 | @track mydata; 6 | @track mycolumns; 7 | @track error; 8 | @api sObjectName; 9 | @api fieldSetName; 10 | @api recordId = ''; 11 | @api sObjectLookupIDField = ''; 12 | @api additionalWhereClause = ''; 13 | 14 | @wire(getSobjectRecords,({ 15 | sObjectName : '$sObjectName', 16 | fieldSetName : '$fieldSetName', 17 | recordId : '$recordId', 18 | sObjectLookupIDField : '$sObjectLookupIDField', 19 | additionalWhereClause : '$additionalWhereClause', 20 | })) 21 | wiredAccounts({error, data}){ 22 | if(data){ 23 | this.mycolumns = data.listColumns; 24 | this.mydata = data.dataTableData; 25 | this.error = undefined; 26 | }else if(error){ 27 | this.error = error; 28 | this.mydata = undefined; 29 | this.mycolumns = undefined; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/lightningDataTable/lightningDataTable.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 46.0 4 | true 5 | LWC Data Table 6 | 7 | lightning__HomePage 8 | lightning__AppPage 9 | lightning__RecordPage 10 | lightningCommunity__Default 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /manifest/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | * 5 | ApexClass 6 | 7 | 8 | * 9 | ApexComponent 10 | 11 | 12 | * 13 | ApexPage 14 | 15 | 16 | * 17 | ApexTestSuite 18 | 19 | 20 | * 21 | ApexTrigger 22 | 23 | 24 | * 25 | AuraDefinitionBundle 26 | 27 | 28 | * 29 | LightningComponentBundle 30 | 31 | 32 | * 33 | StaticResource 34 | 35 | 46.0 36 | -------------------------------------------------------------------------------- /sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "46.0" 11 | } 12 | --------------------------------------------------------------------------------