[SalesForce] How to get value from LWC Lighting Datatable cell and act upon it

I am trying to do something that seems like it should be simple,but I obviously do not understand something.

We have a custom document object, it relates to another custom object. I have a datatable listing the documents on the record page of the custom object it relates to.

The last column has a download icon, I don't want to display any data there just the icon (the 'xxx' in the JS is just testing so there is a value there).

When I say download that is going to be done from a remote service and I have code that will do it, I just need to get the value from this row and pass it to the download code. For whatever reason I can get the data to the onclick function.

I have tried using target. a wide variety of fields, and event. a wide variety of fields. Everything comes back 'undefined' except if I put event.detail (with nothing further) then it always evaluates as the value '1', no matter which row I am clicking on.

I obviously don't understand the most basic parts of passing a value from the table back to the controller, would anyone care to help out?

HTML:

<template>
<lightning-card title="File List">

    <lightning-datatable data={documents} columns={columns} key-field="Id" onclick={handleClick}></lightning-datatable>
</lightning-card>

Javascript:

export default class TestLWC extends LightningElement {
@track columns = [
    {
        label: 'File Name',
        fieldName: 'nameUrl',
        type: 'url',
        typeAttributes: {label: { fieldName: 'Name' },
        target: '_blank'},
        sortable: true
    },
    {
        label: 'File Type',
        fieldName: 'File_Type__c',
        type: 'text',
        sortable: true
    },
    {
        label: 'Related To',
        fieldName: 'relatedTo',
        type: 'url',
        typeAttributes: {label: { fieldName: 'Related_To__c' },
        target: '_blank'},
        sortable: true
    },
    {
        fieldName: 'test',
        label: 'Download',
        cellAttributes: { iconName: 'action:download', onClick: 'handleDownloadClick' }
    }

];
@api recordId;
@track error;
@track documents = [];

handleClick(event) {
    const displayStr = event.detail;
    //I have also tried target here
    alert('hello '+displayStr);

}
//@wire(getAllDocs)
@wire(getRelatedDocs,{recordId: '$recordId'})
wiredDocs(result) {
    const { data, error } = result;
    // eslint-disable-next-line no-console
    console.log('SCH data '+result);
    if(data) {
        let nameUrl;
        let relatedTo;
        let test;
        this.documents = data.map(row => {
            nameUrl = `${row.File_Link__c}`;
            relatedTo = `/${row.Related_To__c}`;
            test='xxx';
            return {...row ,nameUrl,relatedTo,test}
        })
        this.error = null;
    }
    if(error) {
        this.error = error;
        this.opportunities = [];
    }
}

}

Best Answer

You can still use the actions type with a button icon and without the drop down menu. For this, you need to add onrowaction attribute to the lightning-datatable.

Then once you click on the button icon, the function handleRowAction will be invoked based on the action name and event.detail.row captures which row triggered the button click event.

The sample code below is a tweaked version of the example from the LWC guide : Data table with row actions

Playground version

withRowActions.html

<template>
    <div style="height: 300px;">
        <lightning-datatable
                key-field="id"
                data={data}
                columns={columns}
                onrowaction={handleRowAction}>
        </lightning-datatable>
    </div>
    <div class="slds-m-around--medium" style="width: 30rem;">
        <article class="slds-tile">
            <h3 class="slds-tile__title slds-truncate" title="Record details"><a href="javascript:void(0);">Record details</a></h3>
            <div class="slds-tile__detail">
                <dl class="slds-list_horizontal slds-wrap">
                    <dt class="slds-item_label slds-text-color_weak slds-truncate" title="Name">Name:</dt>
                    <dd class="slds-item_detail slds-truncate">{record.name}</dd>
                    <dt class="slds-item_label slds-text-color_weak slds-truncate" title="Balance">Balance:</dt>
                    <dd class="slds-item_detail slds-truncate">
                        <lightning-formatted-number value={record.amount} format-style="currency"></lightning-formatted-number>
                    </dd>
                </dl>
            </div>
        </article>
    </div>
</template>

withRowActions.js

import { LightningElement, track } from 'lwc';
import fetchDataHelper from './fetchDataHelper';

const actions = [
    { label: 'Download', name: 'download' }
];

const columns = [
    { label: 'Name', fieldName: 'name' },
    { label: 'Website', fieldName: 'website', type: 'url' },
    { label: 'Phone', fieldName: 'phone', type: 'phone' },
    { label: 'Balance', fieldName: 'amount', type: 'currency' },
    { label: 'Close At', fieldName: 'closeAt', type: 'date' },
    {type: 'button-icon', typeAttributes: {  
        iconName: 'utility:download',
        label: 'Download',  
        name: 'download',  
        variant: 'bare',
        alternativeText: 'download',        
        disabled: false
    }}
];

export default class DatatableWithRowActions extends LightningElement {
    @track data = [];
    @track columns = columns;
    @track record = {};

    async connectedCallback() {
        this.data = await fetchDataHelper({ amountOfRecords: 100 });
    }

    handleRowAction(event) {
        const actionName = event.detail.action.name;
        const row = event.detail.row;
        switch (actionName) {
            case 'download':
                this.showRowDetails(row);
                break;                      
            default:
        }
    }

    showRowDetails(row) {
        this.record = row;
        console.log(JSON.stringify(row));
        console.log(JSON.stringify(row.name));
    }

}

fetchDataHelper.js (used only display sample data in the table)

const recordMetadata = {
    name: 'name',
    email: 'email',
    website: 'url',
    amount: 'currency',
    phone: 'phoneNumber',
    closeAt: 'dateInFuture',
};

export default function fetchDataHelper({ amountOfRecords }) {
    return fetch('https://data-faker.herokuapp.com/collection', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
        },
        body: JSON.stringify({
            amountOfRecords,
            recordMetadata,
        }),
    }).then(response => response.json());
}
Related Topic