+ Start a Discussion
erikvmerikvm 

Event handler on lightning:datatable button?

I've got a lightning:datatable that looks like this: 
<aura:attribute name="resources" type="Object"/> 
<aura:attribute name="mycolumns" type="List"/> 
<aura:handler name="init" value="{! this }" action="{! c.doInit }"/> 
<lightning:datatable 
data="{! v.resources }" 
columns="{! v.mycolumns }" 
keyField="Id" 
onrowaction="{! c.handleRowAction }" 
hideCheckboxColumn="true" />

with a doInit that looks like this:

doInit: function (component, event, helper) {
        var actions = [
                    { label: 'Select', name: 'selectRecord' },
                ];
        component.set('v.mycolumns', [
                        {type: 'action', typeAttributes: {
                        rowActions: actions,

                        }},
                        {type: "button", typeAttributes: {
                             iconName: 'utility:add',
                             label: '',
                             name: 'selectRecord',
                             title: 'selectRecord',
                             disabled: false,
                             value: 'test',
                             }},
                        {label: 'Resource', fieldName: 'Name', type: 'text'},
                        {label: 'Comment', fieldName: 'Comment__c', type: 'text'},

                    ]);
            },
 
handleRowAction: function (component, event, helper) {
        var action = event.getParam('action');
        var row = event.getParam('row');
        switch (action.name) {
            case 'selectRecord':
                console.log(row.Id);
                console.log('Showing Details: ' + JSON.stringify(row));
                break;

Here's my issue: I want the button to handle the handleRowAction. I don't want a dropdown menu - how can I make my button handle the action? What's the point of having a button on the lightning:datatable if I can't do anything with it? As of now it seems that only "action" can handle stuff like "select this row" etc.
 
Best Answer chosen by erikvm
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
Hi, 
You can achieve that behaviour in the following way
doInit: function (component, event, helper) {
        component.set('v.mycolumns', [
                        {type: "button", typeAttributes: {
                             iconName: 'utility:add',
                             label: '',
                             name: 'selectRecord',
                             title: 'selectRecord',
                             disabled: false,
                             value: 'test',
                             variant: {fieldName: 'variantValue'}
                             }},
                        {label: 'Resource', fieldName: 'Name', type: 'text'},
                        {label: 'Comment', fieldName: 'Comment__c', type: 'text'},

                    ]);
            },

I have added variant type attribute to the button you are adding
variant: {fieldName: 'variantValue'}
and in your handleRowAction method for the case of type 'selectRecord'  call the helper method 'addRow' as show below, I am setting the variant of the selected row's button to something else so that I can show that the button is clicked. You can create 'fieldName'  for any of the typeAttributes and achieve the same.
addRow: function (cmp, row) {
        var data = cmp.get('v.data');
        data = data.map(function(rowData) {
            if (rowData.Id === row.Id) {
                rowData.variantValue = 'Brand'; // rowData.variantValue = 'Inverse'
            }
            return rowData;
        });
        cmp.set("v.data", data);
 }

All Answers

MagulanDuraipandianMagulanDuraipandian
Checkt this example - http://www.infallibletechie.com/2018/04/lightningdatatable-with-buttons-in.html with two buttons in lightning:datatable.
erikvmerikvm
This is, unfortunately, not working. I tried copying everything step by step and I can't reproduce what he's done...
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
Try removing the action in the columns? something like below. this may not be working because there are two actions name: 'selectRecord'?
doInit: function (component, event, helper) {
        component.set('v.mycolumns', [
                        {type: "button", typeAttributes: {
                             iconName: 'utility:add',
                             label: '',
                             name: 'selectRecord',
                             title: 'selectRecord',
                             disabled: false,
                             value: 'test',
                             }},
                        {label: 'Resource', fieldName: 'Name', type: 'text'},
                        {label: 'Comment', fieldName: 'Comment__c', type: 'text'},

                    ]);
            },
erikvmerikvm
Thanks Ashwin, I did actually find a solution to it eventually. Now, another concern is that I want to highlight the the / button clicked.. lightning:datatable doesn't seem to provide this type of service? With regular lightning buttons I could've gotten the button through event.getSource(), this doesn't exist in datatables, does it?
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
Hi, 
You can achieve that behaviour in the following way
doInit: function (component, event, helper) {
        component.set('v.mycolumns', [
                        {type: "button", typeAttributes: {
                             iconName: 'utility:add',
                             label: '',
                             name: 'selectRecord',
                             title: 'selectRecord',
                             disabled: false,
                             value: 'test',
                             variant: {fieldName: 'variantValue'}
                             }},
                        {label: 'Resource', fieldName: 'Name', type: 'text'},
                        {label: 'Comment', fieldName: 'Comment__c', type: 'text'},

                    ]);
            },

I have added variant type attribute to the button you are adding
variant: {fieldName: 'variantValue'}
and in your handleRowAction method for the case of type 'selectRecord'  call the helper method 'addRow' as show below, I am setting the variant of the selected row's button to something else so that I can show that the button is clicked. You can create 'fieldName'  for any of the typeAttributes and achieve the same.
addRow: function (cmp, row) {
        var data = cmp.get('v.data');
        data = data.map(function(rowData) {
            if (rowData.Id === row.Id) {
                rowData.variantValue = 'Brand'; // rowData.variantValue = 'Inverse'
            }
            return rowData;
        });
        cmp.set("v.data", data);
 }
This was selected as the best answer
erikvmerikvm
Thanks @Ashwin, this works partly, but it doesn't make an unselected go back to neutral? I only want the one button I clicked on last to be highlighted. Currently, all buttons clicked changes to "Brand" in variant
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
addRow: function (cmp, row) {
        var data = cmp.get('v.data');
        data = data.map(function(rowData) {
            if (rowData.Id === row.Id) {
                if(rowData.variantValue === 'Brand'){
                    rowData.variantValue = 'Neutral';
                } else{
                    rowData.variantValue = 'Brand';
                }
                
            }
            return rowData;
        });
        cmp.set("v.data", data);
    }
The above code will help you to toggle.

This works for me , can you console and check if the data you are getting is bound one to the datatable? and if you could console the console.log(row.Id) and check it will be good. 

I had the similar issue because I had in my code (Id as id and its case sensitive). If you still have any issues, if you could post the code it will be helpful.

Thanks
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
Because of that case sensitive thing 
if (rowData.Id === row.Id)

the above check might have become undefined === undefined and its making all the rows as variant 'Brand'
erikvmerikvm
Awesome, this does work Ashwin. I just needed to add an else clause. Thanks a ton!
erikvmerikvm

Do you know if it's possible to set a default value for the iconName? Ideally I would like to have it go from "iconName: xxxx" AND "variant: xxxx"

to "iconName: yyyy" and "variant: "yyyy". However, if no button is clicked (just when the component first renders, all buttons just appear as a thin line, as nothing is clicked. 

I tried something like 

variant: {fieldName: 'variantValue'}
iconName: {fieldName: 'imageValue'}
and then
 
if (rowData.Id === row.Id) {
                if(rowData.variantValue === 'Brand'){
                    rowData.variantValue = 'Neutral';
                    rowData.imageValue = 'utility:add';
                } else{
                    rowData.variantValue = 'Brand';
                    rowData.imageValue = 'utility:check';
                }

However, since nothing is yet clicked, the buttons just appear as "-----". Everything works fine when one button is clicked, but not before that.
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
I will check if there is an easy way to set default in the column data (ideally there should be), but we can on the init of the component after the server side callback to retrieve the data before we set the data in the attribute, we can do the same as we did on the addRow method 
setDefault: function (cmp) {
        var data = cmp.get('v.data');
        data = data.map(function(rowData) {
                    rowData.variantValue = 'Brand';
            }
            return rowData;
        });
        cmp.set("v.data", data);
    }
But yes ideally we should not be iterating through data for setting default. 
erikvmerikvm
Yeah, iterating through the list on init will slow things down I'm afraid
Ashwin Kumar SrinivasanAshwin Kumar Srinivasan
Agreed, if I find nicer way I will update you. It will be worth to post a separate question on this as well :).
erikvmerikvm
Truly appreciate your help. Let me know if you find a way
karishma gurjar 3karishma gurjar 3
Hi Ashwin,

I am also implementing Button in Lightning table, I am succeeded to populate the label values on button. Just the text is starting from center. I need to start the text from left side.

User-added image

here is my code:

doInit: function(component, event, helper) {
        component.set('v.mycolumns', [
            
            {label: 'Report Name',
            type: 'button',
             typeAttributes: {
            title: 'Preview',
            variant: 'brand',
            alternativeText: 'View',
            disabled: false,
            label: { fieldName: 'Name' },
            name: { fieldName: 'Name' },
            }},
        ]);
        helper.getPBListHandler(component,event);      
    },