5

I've been stuck on this issue for a few hours now and don't seem to be getting any closer to resolving it.

I currently have a Lightning-Datatable with pagination that renders 20 rows at a time. When the user clicks the next or previous page button it swaps out the data for the next 20 records. This is working fine.

When the table loads for the first time, my 'selected-rows' array is being read and the correct rows are ticked. However, when jumping to the next page and changing the data source, the datatable stops rendering any selected-row values even though it is in the list. If I jump back to the first page (which originally had checked rows) the rows remain unchecked.

I have tried updating both the selected-rows and data values to force the pages to refresh but I've had no luck. Do you know why this may be and how I can resolve this matter?


My Datatable

<lightning-datatable
    key-field="Id"
    data={homes}
    columns={columns}
    selected-rows={selectedRows}
    onsort={sortColumns}
    sorted-by={sortField} 
    sorted-direction={sortDirection}
    hide-checkbox-column={hideCheckboxes}
    resize-column-disabled=true>
</lightning-datatable>

My JS

export default class HomesList extends LightningElement {
    @api recordId;

    @track columns = columns;
    @track homes = [];
    @track tableLoadingState = true;
    @track isEditing = false;
    @track totalPages = 1;
    @track jumpToPageNum = 1;

    selectedIds = [];
    sortField = "Name";
    sortDirection = "asc";
    pageNum = 1;

    get selectedRows() {
        if (this.isEditing) {
            return this.selectedIds;
        }
        return [];
    }

    get hideCheckboxes() {
        return !this.isEditing;
    }

    get getPageNum() {
        return this.pageNum + " / " + this.totalPages;
    }

    get hasNextPage() {
        return this.pageNum >= this.totalPages;
    }

    get hasPreviousPage() {
        return this.pageNum <= 1;
    }

    connectedCallback() {
        this.getSelectedHomes();
        this.getHomes();
    }

    sortColumns(event) {
        this.sortField = event.detail.fieldName;
        this.sortDirection = event.detail.sortDirection;
        this.getHomes();
    }

    toggleEdit() {
        this.isEditing = !this.isEditing;
        this.pageNum = 1;
        this.getHomes();
    }

    getFirstPage() {
        this.pageNum = 1;
        this.getHomes();
    }

    getNextPage() {
        this.pageNum++;
        this.getHomes();
    }

    getPreviousPage() {
        this.pageNum--;
        this.getHomes();
    }

    getLastPage() {
        this.pageNum = this.totalPages;
        this.getHomes();
    }

    getHomes() {
        this.tableLoadingState = true;
        getHomes({ contractId: this.recordId, isEditing: this.isEditing, sortField : this.sortField, sortDirection : this.sortDirection, pageNum : this.pageNum})
            .then(result => {
                this.totalPages = Object.keys(result)[0];
                this.homes = Object.values(result)[0];
                this.error = undefined;
                this.tableLoadingState = false;     
            })
            .catch(error => {
                this.error = error;
                this.homes = undefined;
                this.totalPages = 1;
                this.tableLoadingState = false;
            });
    }

    getSelectedHomes() {
        getSelectedHomes({ contractId: this.recordId })
            .then(result => {
                this.selectedIds = result;
                this.error = undefined;
            })
            .catch(error => {
                this.error = error;
                this.selectedIds = [];
            });
    }
}

My Controller

@AuraEnabled
public static List<Id> getSelectedHomes(String contractId) {
    String query = 'SELECT Homes__c FROM Contract_Home__c WHERE Contract__c = \'' + contractId + '\' LIMIT 10000';
    List<Contract_Home__c> contractHomes = Database.query(query);

    List<Id> selectedHomes = new List<Id>();
    for (Contract_Home__c contractHome : contractHomes) {
        selectedHomes.add(contractHome.Home__c);
    }

    return selectedHomes;
}

Thanks!

2
  • This controller looks incomplete, cant see getHomes apex code Jun 6, 2019 at 9:28
  • Hi Pranay, sorry I didn't include the getHomes method. If it helps it just returns a list of Homes objects with the fields that appear in the columns.
    – Danturr
    Jun 6, 2019 at 9:34

3 Answers 3

2

There is no two-way binding, the rows you selected won't be in selected-rows={selectedRows} . You have use onrowselection attribute on datatable.

<lightning-datatable
        key-field="Id"
        data={homes}
        columns={columns}
        selected-rows={selectedRows}
        onsort={sortColumns}
        sorted-by={sortField}
        sorted-direction={sortDirection}
        hide-checkbox-column={hideCheckboxes}
        onrowselection={getSelectedName}>
        resize-column-disabled=true>
</lightning-datatable>

and in JS store it somewhere like :

getSelectedName(event) {
            const selectedRows = event.detail.selectedRows;

            for (let i = 0; i < selectedRows.length; i++){
                 if (!selectedId.includes(selectedRows[i].Id))
                 selectedId.push(selectedId);
            }


        }
1
  • Hi Pranay, thanks for your help. I understand that, however my issue is that when I change the table data but keep the selected-rows the same, the rows are unselected even though the exist in the selectedIds array. I imagine this is a rendering issue, however, I just can seem to work it out. I've tried using RenderedCallback() but that doesn't seem to work.
    – Danturr
    Jun 6, 2019 at 14:24
2

I know this is an old post but none of the other solutions seem to solve the real issue. I ended up finding the solution after a whole day wrestling with the table.

Problem: The problem is whenever the table stops displaying the selected records (in your case its displaying records on the next page), it thinks that that data on the previous page is no longer selected so it calls the onrowselection function again even with a newly created even.detail.selectedRows list which will be an empty array since nothing is selected on the second page yet.

Solution: keep track of selectedrowsId. whenever onrowselection gets called again have it check to see if the data your table is displaying (whatever value you have binded to the table data attribute) contains all the selectedrowsId. If it doesn't contain it then that mean the user does not have access to that record therefor it should not get deleted. Find that record from your raw table data and push it to your event.detail.selectedRows to include it back in the selected rows.

Hopefully this code makes more sense.

 getSelectedRows(event) {
    const selectedRows = event.detail.selectedRows;
    
    // Add back record if not visible to user
    this.selectedRowsId.forEach(id => {
        if(!this.tableData.some(data => data.id === id))
            selectedRows.push(this.orders.find(data => data.id === id));
    });
    // Keep track of selected rows
    selectedRows.forEach(row => {
        if(!this.selectedRowsId.includes(row.id)) {
            this.selectedRowsId.push(row.id)
        }
    });
}
1
  • Does anyone try the above approach with pagination? Jan 4, 2021 at 14:18
0

I guess you take care of updating the selectedIds when you swap out the table data. In that case I think you're simply missing to make the selectedRows property tracked. Or rather to make the private property selectedIds tracked:

    @track selectedIds = [];

You must log in to answer this question.

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