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';
}
}
@karanam-narendra
Copy link

sir you have not included picklist in the data table code.

@pdealwiswiley
Copy link

Thank you for sharing your knowledge with us. I have few questions to ask on the above Toggle button implementation.

  1. How I get rowId and toggle button state from handleSelectedRec(event) in App ? I'm getting empty value for console.log(event.detail.value) ..
  2. Event is empty in state: event.target.checked. So could not retrieve the status from there as well.

Could you help me with the above questions?

@geekyakshay
Copy link
Author

geekyakshay commented Jun 9, 2021

@pdealwiswiley
Can you share your code-snippet of hows it's configured in your code?
Check if you are passing record id (rowId) in the type attribute for the column configuration and it is received in the ToggleButtonOutput.js controller using console log.

@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