[SalesForce] Refresh specific LDS cache entry in lightning web component

To demonstrate a specific issue with LDS cache, I have created simple lightning web component that displays list of accounts (filterable by account type) using lightning-combobox and lightning-datatable. The source code for this component can be accessed in this git repo. [Since this is a demo component, I may have skipped best practices and detailed comments, but the code is fairly easy to understand.]. High level details of the component are given below:

  • LWC uses lightning-combobox to display the account types and is used to filter the result set. Based on a user selected type value, a (un)filtered list of accounts is displayed in a lightning-datatable. The account name field is editable in the data table.
  • Component wires custom apex methods to fetch account types and list of accounts; and uses lightning\uiRecordApi to update changes made to the account name. refreshApex method is used to force refresh on LDS cached result.
  • Apex class has 2 methods – One for fetching the list of distinct Account Types and the other for fetching list of accounts based on the account type.

enter image description here

Problem Statement:

After updating a record, LDS cache is not refreshed as expected. Replication steps mentioned below:

  1. Note down the first 2 account records (account name) for the type Customer - Direct.
  2. Select Customer - Direct in the combobox to get the filtered result set.
  3. Edit the account names for the records noted down earlier and click 'Save' to update the data.
  4. Component is refreshed with the latest updated data.
  5. Select All Types in the combobox to get list of all accounts. It can be observed that the updated records do not display the latest values (but old values from LDS cache).
  6. Switch back to Customer - Direct to see the updated values.

This indicates that there are distinct LDS cache entries for each filtered list of accounts and only the cache corresponding to the current displayed result set (or the one fetched by last @wire adapter execution) is refreshed. The scenario presented here is a very simple one, but there could be slightly complex scenarios. For example, the filter values are fetched from a multi-select picklist field and the record(s) could be present n (>2) number of filtered result sets displayed in the data table. This would require all n LDS cache entries to be refreshed.

What I already know or tried so far:

  • Use imperative apex calls for accounts retrieval as well as updating and use getRecordNotifyChange (lightning\uiRecordApi) & refreshApex to have complete control over the displayed data. By taking this approach, I might have to sacrifice the usage of ui*Api methods as well as LDS cache.
  • Use the same approach as above, but mark apex methods as cacheable [@AuraEnabled(cacheable=true)]. Doing this doesn't help either because this still doesn't refresh all the cache entries.

Solution: Work-around to solve this problem is provided as answer. But I would like to know if there is any better approach (or if I missed out on a really simple logic) to solve this problem.

Note: I've tried to provide as much details as I could to illustrate the problem. Feel free to comment, if any part of this question is unclear. Also, in the solution, I may have skipped some best coding practices since that's not the problem at focus. Suggestions are welcome.

Best Answer

After testing out your code and quite a bit of research I was finally able to do it, I found it in the documentation and was able to update the cache values using a function: getRecordNotifyChange()

enter image description here

https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.data_table_inline_edit

The very last example should solve your scenario

async handleSave(event){
    const updatedFields = event.detail.draftValues;
    // Prepare the record IDs for getRecordNotifyChange()
    const notifyChangeIds = updatedFields.map(row => { return { "recordId": row.Id } });
    console.log(notifyChangeIds,' : notifyChangeIds');

    const recordInputs = event.detail.draftValues.slice().map(draft => {
        const fields = Object.assign({}, draft);
        return {fields};
    });
    const promises = recordInputs.map(recordInput => updateRecord(recordInput));
    Promise.all(promises).then(() => {
        this.dispatchEvent(
            new ShowToastEvent({
                title: SUCCESS_TITLE, 
                message: SUCCESS_MSG, 
                variant: SUCCES_VARIANT
            })
        );
        console.log(notifyChangeIds,' : notifyChangeIds');
        getRecordNotifyChange(notifyChangeIds);
        // Display fresh data in the datatable
        refreshApex(this.accounts)
        // Clear all draft values in the datatable also hides the save and cancel button
        this.draftValues = [];
        
    })
    .catch(error =>{
        console.log('error: ',error);
        this.dispatchEvent(
            new ShowToastEvent({
                title: ERROR_TITLE, 
                message: error.body.message, 
                variant: ERROR_VARIANT
            })
        );
    });
}

This works perfectly the cache value gets updated issue seems with the way filtering is working just filter the data client side ..that way you can avoid two lds cache entries

Related Topic