2

Infinite scroll in LWC datatable is calling the loadMoreData() function multiple times. This increments the offset multiple times but wire is not called multiple times and hence some data gets skipped while loading. Also, the spinner at the end is not showing. I used wire to get the data from database. I am not able to figure out why datatable is making multiple function calls. I did research but was not able to figure out the reason. Please guide. Thanks!

I checked these sites:

  1. https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentation
  2. https://salesforcespace.blogspot.com/2020/02/lwc-audit-log-viewer-using-infinite.html

HTML

<div class="slds-table_col-bordered slds-table_bordered slds-table_striped" style="height:15rem;">
                        <lightning-datatable key-field="id" data={data} columns={columns} onrowselection={handleRowActions} default-sort-direction={defaultSortDirection}
                        sorted-direction={sortDirection}
                        sorted-by={sortedBy}
                        onsort={onHandleSort}
                        enable-infinite-loading
                        onloadmore={loadMoreData}>
                        </lightning-datatable>
</div>

Javascript

@wire(downloadRelatedListControllerLWC, { Id: '$recordId',PageSize: '$PageSize',counterLWC:'$counter' }) wired(result) {
        window.console.log('in wire - pagesize:'+this.PageSize+'counter:'+this.counter);
        this.refreshTable = result; //for refreshing the datatable
        //rest of wire code here
}


loadMoreData(event) {
        window.console.log('inside load more data');
        event.target.isLoading = true; //showing the spinner
        if(this.count.data > this.counter){
            event.target.isLoading = false; //hiding the spinner
            window.console.log('incrementing counter'+this.counter);
            this.counter=this.counter+10; //This statement is called multiple times. Hence offset is incremented multiple times
            window.console.log('incremented counter'+this.counter);
            return refreshApex(this.refreshTable); //calling the wire. Wire is not called multiple times when offset is incremented. Offset is incremented 2-3 times and then wire is incremented
        } 
}

Debug logs:

Red represents scrolls and yellow represents calls

Updates

If I use constructor instead of wire to access apex code, I get the following error

enter image description here

1 Answer 1

3

Looking at the example from the documentation, I think, using an imperative apex will be more appropriate here. So you need to fetch more data whenever load more data is called, then concatenate that to the original data attribute which is bound to the table. Refer to the below example from the documentation. I have added some comments(starting with // **) to that.

HTML

<template>
    <div style="height: 500px">
        <lightning-datatable
                columns={columns}
                data={data}
                key-field="id"
                enable-infinite-loading
                onloadmore={loadMoreData}>
        </lightning-datatable>
    </div>
    {loadMoreStatus}
</template>

Javascript:

import { LightningElement } from 'lwc';

export default class DatatableExample extends LightningElement {
    @track data = [];
    @track columns = columnsDefs;
    @track loadMoreStatus;
    @api totalNumberOfRows;

    loadMoreData(event) {
            //Display a spinner to signal that data is being loaded
            event.target.isLoading = true;
            //Display "Loading" when more data is being loaded
            this.loadMoreStatus = 'Loading';
            fetchData(50) /// ** call your apex method here.
                .then((data) => {
                    if (data.length >= this.totalNumberOfRows) {
                        event.target.enableInfiniteLoading = false;
                        this.loadMoreStatus = 'No more data to load'; // ** end of data
                    } else {
                        const currentData = this.data;
                        //Appends new data to the end of the table
                        const newData = currentData.concat(data); // ** concat data
                        this.data = newData; // ** replace data.
                        this.loadMoreStatus = '';
                    }
                    event.target.isLoading = false;
                }));
        }
}
11
  • I honestly think imperative apex is always the safest approach instead of @wire, if this your experience as well? When do you choose @wire over imperative?
    – Atlas Can
    Mar 27, 2020 at 9:04
  • If I use an imperative function, I'll have to call it in the constructor to load initial data. I use @api recordId and it cannot be used in constructor. Hence I'll need wire.
    – Koustubh
    Mar 27, 2020 at 9:19
  • 1
    @AtlasCan For fetching data from the database, my first preference is wired methods. wire methods save a lot of work on customization. Also, it is faster as it loads data from the cache. You can use refreshApex whenever you want to get data from the database. It reloads data and rerenders every dependent component if any of the attribute(parameter)'s value is changed. The primary use of imperative apex is DML operations. Also, there are exceptions where you cannot use refreshApex and you want to skip the cache while getting the data, like the one in this post, then use imperative. Mar 27, 2020 at 9:19
  • @Koustubh did you get any error when you used recordId in the constructor? Mar 27, 2020 at 9:23
  • 1
    @Koustubh instead of constructor use connectedCallback() to call imperative method. Mar 27, 2020 at 9:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .