Skip to content

Instantly share code, notes, and snippets.

@geekyakshay
Last active March 7, 2024 17:58
Show Gist options
  • Save geekyakshay/a71fa3fcf78beadd2952407f3945e382 to your computer and use it in GitHub Desktop.
Save geekyakshay/a71fa3fcf78beadd2952407f3945e382 to your computer and use it in GitHub Desktop.
Implement custom columns in lightning-datatable LWC
<template>
<!-- Embed custom datatable component in your parent component -->
<c-custom-datatable
key-field="Id"
data={toggleExampleData}
hide-checkbox-column
columns={toggleExampleColumns}
onselectedrec={handleSelectedRec}>
</c-custom-datatable>
</template>
/*
* @File Name : app.js
* @Description : Parent most component where custom-datatable will be embedded.
* @Author : Akshay Poddar
* @Last Modified On : 29/6/2020, 8:02:44 pm
**/
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
//Sample hard-coded data to demonstrate how to structure (generate) data for custom columns
toggleExampleData = [
{Id: 1, isSelected: true, name: 'Google', website: 'https://google.com'},
{Id: 2, isSelected: false, name: 'Facebook', website: 'https://facebook.com'},
{Id: 3, isSelected: true, name: 'DevLife', website: 'https://devlife.tech'},
{Id: 4, isSelected: false, name: 'Gmail', website: 'https://gmail.com', isDisabled: true}
];
//Sample hard-coded column data to demonstrate how to structure (generate) column data for custom columns
toggleExampleColumns = [
{ label: 'Custom Buttons', fieldName: 'isSelected', type: 'toggleButton',
typeAttributes: {
buttonDisabled: { fieldName: 'isDisabled' },
rowId: { fieldName: 'Id' },
}
},
{ label: 'Service', fieldName: 'name', iconName: 'custom:custom18' },
{ label: 'Website', fieldName: 'website', type: 'url', iconName: 'custom:custom20' },
];
//Handler for custom column interations - like handle what to do when toggle button is pressed
handleSelectedRec(event){
console.log(event.detail.value);
//Write your logic to handle button interations
}
}
<template>
<!--Leave this template blank - Contents will be rendered dynamically-->
</template>
/*
* @File Name : customDatatable.js
* @Description : Common JS for all custom data type HTML templates, Contains
* logic to define custom data type and link with html template.
* @Author : Akshay Poddar
* @Last Modified On : 29/6/2020, 8:02:44 pm
**/
import LightningDatatable from 'lightning/datatable';
import toggleButtonColumnTemplate from './toggleButtonColumnTemplate.html';
import richTextColumnTemplate from './richTextColumnTemplate.html';
import iconColumnTemplate from './iconColumnTemplate.html';
export default class CustomDatatable extends LightningDatatable {
static customTypes = {
toggleButton: {
template: toggleButtonColumnTemplate,
standardCellLayout: true,
typeAttributes: ['buttonDisabled', 'rowId'],
}
};
}
<template>
<!--HTML template which connect custom column component with custom datatable component-->
<c-toggle-button-output
checked={value}
button-disabled={typeAttributes.buttonDisabled}
row-id={typeAttributes.rowId}>
</c-toggle-button-output>
</template>
<template>
<!--Custom component which will be rendered as each cell in custom column in datatable-->
<lightning-input
type="toggle"
label="Basic option"
variant="label-hidden"
message-toggle-active="Selected"
message-toggle-inactive={getInactiveMsg}
checked={checked}
disabled={buttonDisabled}
onchange={handleToggle}>
</lightning-input>
</template>
/*
* @File Name : toggleButtonOutput.js
* @Description : JS file which contains attribute declaration for custom data type
* which can be used to customize columns even further. It also contains
* code to call custom event whenever button gets clicked (interation with
* column is to be defined).
* @Author : Akshay Poddar
* @Last Modified On : 29/6/2020, 8:02:44 pm
**/
import { LightningElement, api } from 'lwc';
export default class ToggleButtonOutput extends LightningElement {
@api checked = false;
@api buttonDisabled = false;
@api rowId;
handleToggle(event) {
const event = CustomEvent('selectedrec', {
composed: true,
bubbles: true,
cancelable: true,
detail: {
value: { rowId: this.rowId, state: event.target.checked }
},
});
this.dispatchEvent(event);
}
get getInactiveMsg(){
return this.buttonDisabled?'Disabled':'Not Selected';
}
}
@pdealwiswiley
Copy link

pdealwiswiley commented Jun 11, 2021

Hi @geekyakshay.

I have used the same above code posted by you and customize it a little bit.

when clicking the toggle button I can't get rowId and toggle button state from handleSelectedRec(event) in App.
This is the output I get from the console log. Only RowId is getting and it is getting at togglebuttonoutput.js.

Togglebuttonoutput handleToggle rowId 10
togglebuttonoutput.js:4 Togglebuttonoutput handleToggle state: undefined
customdatatableapp.js:4 Customdatatableapp handleSelectedRec event.detail.value =[object Object]
customdatatableapp.js:4 Customdatatableapp handleSelectedRec this.rowId =undefined
customdatatableapp.js:4 Customdatatableapp handleSelectedRec this.userId =undefined
customdatatableapp.js:4 Customdatatableapp handleSelectedRec event.target.checked =undefined

Please find the full app codes uploaded in Google Drive.

Download Customdatatableapp Package

Below are the codes.

customdatatableapp.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>51.0</apiVersion> <description>Customdatatableapp</description> <isExposed>true</isExposed> <masterLabel>Customdatatableapp</masterLabel> <targets> <target>lightning__RecordPage</target> <target>lightning__AppPage</target> <target>lightning__HomePage</target> <target>lightning__Tab</target> </targets> </LightningComponentBundle>

customdatatableapp.html
`


                <c-custom-datatable
                        key-field="UserId"
                        data={data}
                        columns={columns}
                        onselectedrec={handleSelectedRec}
                        selected-rows= {selectedRows}>
                </c-custom-datatable>
            </div>
        </div>
  </lightning-card>

`

customdatatableapp.js
`import { LightningElement,api,track,wire } from 'lwc';

export default class Customdatatableapp extends LightningElement {

@track toggleExampleData = [
{UserId: 1, FullName: 'Jhon Doe1',Email: 'jhondoe1@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 2, FullName: 'Jhon Doe2',Email: 'jhondoe2@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 3, FullName: 'Jhon Doe3',Email: 'jhondoe3@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 4, FullName: 'Jhon Doe4',Email: 'jhondoe4@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 5, FullName: 'Jhon Doe5',Email: 'jhondoe5@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 6, FullName: 'Jhon Doe6',Email: 'jhondoe6@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE' ,isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 7, FullName: 'Jhon Doe7',Email: 'jhondoe7@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 8, FullName: 'Jhon Doe8',Email: 'jhondoe8@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 9, FullName: 'Jhon Doe9',Email: 'jhondoe9@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 10, FullName: 'Jhon Doe10',Email: 'jhondoe10@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'FALSE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 11, FullName: 'Jhon Doe11',Email: 'jhondoe11@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'FALSE',LastLoginDate:'2021-01-01 11:00:00'},
{UserId: 12, FullName: 'Jhon Doe12',Email: 'jhondoe12@gmail.com',ProfileName: 'Admin',RoleName: 'Support',isFrozen: 'TRUE',isDeactivate: 'TRUE',LastLoginDate:'2021-01-01 11:00:00'}
];

@track columns = [

   {
     label: 'Name',
     fieldName: 'FullName',
     type: 'text',
     sortable: true,
     cellAttributes: {
       alignment: 'left'
     }
   },
   {
     label: 'Email',
     fieldName: 'Email',
     type: 'text',
     sortable: true,
     cellAttributes: {
       alignment: 'left'
     }
   },
   {
     label: 'Profile',
     fieldName: 'ProfileName',
     type: 'text',
     sortable: true,
     cellAttributes: {
       alignment: 'left'
     }//,
    // initialWidth: 170,
   },
   {
     label: 'Role',
     fieldName: 'RoleName',
     type: 'text',
     sortable: true,
     cellAttributes: {
       alignment: 'left'
     }
   },
   {
     label: "Last Login Date",
     fieldName: "LastLoginDate",
     type: "date",
     typeAttributes: {
       year: "numeric",
       month: "2-digit",
       day: "2-digit",
       hour: "2-digit",
       minute: "2-digit",
       second: "2-digit"
     },
     sortable: true,
     cellAttributes: {
       alignment: 'left'
     }
   },
   {
     label: 'Frozen',
     fieldName: 'isFrozen',
     type: 'text',
     sortable: false,
     cellAttributes: {
       alignment: 'left'
     }
   },
   {
     label: 'Deactivate?',
     fieldName: 'isDeactivate',
     type: 'text',
     sortable: false,
     cellAttributes: {
       alignment: 'left'
     }
   },
   { label: 'Custom Buttons',
     fieldName: 'deactivateStatus',
     type: 'toggleButton',
     typeAttributes: {
           buttonDisabled: { fieldName: 'isDisabled' },
           rowId: { fieldName: 'UserId' },
     }
   }
 ];



 // Track Gloabal variables
 @track showLoadingSpinner = false;
 @track error;
 @track allSelectedRows =[];

// Initial Method Call
connectedCallback() {
try {
this.showLoadingSpinner = true;
if (this.toggleExampleData) {
var tempUserList = [];
this.toggleExampleData.forEach((record) => {
let tempUserRec = Object.assign({}, record);
tempUserRec.recordLink = '/' + tempUserRec.UserId;
if (tempUserRec.isDeactivate == 'TRUE')
{
tempUserRec.deactivateStatus = true;
}
else
{
tempUserRec.deactivateStatus = false;
}
tempUserList.push(tempUserRec);
});

                      this.data = tempUserList;


            }
         }
            catch (error) {
              this.error = error;
             } finally {
               this.showLoadingSpinner = false;
             }

}

// Initial Method Call - Populate data on UI
@api
get selectedRows() {
return this.allSelectedRows;
}
set selectedRows(value) {
this.allSelectedRows = value;
}
@api getSelected() {
var el = this.template.querySelector('c-custom-datatable');
return el.getSelectedRows();
}

handleSelectedRec(event){
console.log('Customdatatableapp handleSelectedRec event.detail.value ='+event.detail.value);
console.log('Customdatatableapp handleSelectedRec this.rowId ='+this.rowId);
console.log('Customdatatableapp handleSelectedRec this.userId ='+this.UserId);
console.log('Customdatatableapp handleSelectedRec event.target.checked ='+event.target.checked);
//Write your logic to handle button interations
}
}`

customDatatable.html
`

`

customDatatable.js
`import LightningDatatable from 'lightning/datatable';
import toggleButtonColumnTemplate from './toggleButtonColumnTemplate.html';

export default class CustomDatatable extends LightningDatatable {

static customTypes = {
    toggleButton: {
        template: toggleButtonColumnTemplate,
        standardCellLayout: true,
        typeAttributes: ['buttonDisabled', 'rowId'],
    }
};

}`

toggleButtonColumnTemplate.html
<template> <c-togglebuttonoutput checked={value} button-disabled={typeAttributes.buttonDisabled} row-id={typeAttributes.rowId}> </c-togglebuttonoutput> </template>

togglebuttonoutput.html
<template> <div > <lightning-input type="toggle" label="Basic option" variant="label-hidden" message-toggle-active="Selected" message-toggle-inactive={getInactiveMsg} checked={checked} disabled={buttonDisabled} onchange={handleToggle}> </lightning-input> </div> </template>

togglebuttonoutput.js
`import { LightningElement, api} from 'lwc';

export default class Togglebuttonoutput extends LightningElement {

@api checked = false;
@api buttonDisabled = false;
@api rowId;

handleToggle(event) {

const eventnew = CustomEvent('selectedrec', {
composed: true,
bubbles: true,
cancelable: true,
detail: {
value: { rowId: this.rowId, state: event.target.checked }
},
});
this.dispatchEvent(eventnew);
console.log('Togglebuttonoutput handleToggle rowId '+ this.rowId);
}

get getInactiveMsg(){
    return this.buttonDisabled?'Disabled':'Not Selected';
}

}`

I need to get rowId and toggle button state(true or false selected) from handleSelectedRec(event) in App. Could you please help me on this? I am really stuck on this issue.

@pdealwiswiley
Copy link

Hi @geekyakshay,

I found out the issue of why it is not console logging values inside the parent's handleSelectedRec method.

handleSelectedRec(event){ console.log('Customdatatableapp handleSelectedRec event.detail.value ='+event.detail.value.rowId); console.log('Customdatatableapp handleSelectedRec event.detail.value ='+event.detail.value.state); }

The dispatch event values has to be capture as below. Then it is working fine.
event.detail.value.rowId
event.detail.value.state

Thank you for your help and knowledge sharing @geekyakshay. This sharing helps me a lot to build my requirement quickly and easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment