2

I have a parent LWC with a list of records and a child LWC which allows the user to perform actions on the record.

The child uses dispatchEvent and CustomEvent to notify the parent after changes have been made to the record, so that the parent can refresh the list of records.

Unfortunately, refreshApex in the parent is not always working...

Here is the code.....

parent component

<template>
  // contains a list of records, removed for brevity 
  <c-child-record-detail onback={handleBack} record-id={recordId}></c-child-record-detail>
</template>

parent JavaScript

import { LightningElement, wire } from "lwc";
import { refreshApex } from "@salesforce/apex";
import getRecords from "@salesforce/apex/MyController.getRecords";

export default class MyLWC extends LightningElement {

    records;
    wiredResult;
    records; // used to render
    recordList; // used to store the original set from the server
    filterValue = "";
    recordId;

    @wire(getRecords) wiredRecords(value) {

        this.wiredResult = value;
        const { data, error } = value;
        if (data) {
            this.error = null;
            this.recordList = data;
            this.filterList();
        } else if (error) { ... }
    }

    refreshList() {
        return refreshApex(this.wiredResult);
    }

    handleBack() {
        this.recordId = null;
        this.refreshList();
    }

    handleFilterChange(event) {
        this.filterValue = event.detail.value;
        this.filterList();
    }

    filterList() {
        switch (this.filterValue) {
            case "Status1":
                this.records = this.recordList.reduce(this.exampleReducer, []);
                break;

            // many other cases removed for brevity 
        }
    }

    exampleReducer = (accumulator, currentValue) => {
        if (currentValue.Status__c === "example") {
            accumulator.push(currentValue);
            return accumulator;
        }
        return accumulator;
    };

    // many other reducers, removed for brevity 

    handleRowClick(event) {
        this.recordId = event.currentTarget.dataset.recordId;
    }
}

I've tried very hard to reduce the code example down without losing its essence.

You will notice that I am doing client side filtering using reduce.

The c-child-record-detail component is reasonably complex, but the problem related to two buttons which are used to finish looking at the record, so we can go back to the list.

child component

child button A JavaScript

handleButtonAClick() {
    updateAsSomeSubStatus({ recordId: this.recordId}).then(result => {
        if (result === true) {
            this.backToList();
        }
    }).catch(error => this.handleError(error));
}

child button A Apex

@AuraEnabled
public static Boolean updateAsSomeSubStatus(Id recordId) {
   try {
       Opportunity record = new Opportunity(Id = recordId);
       record.Sub_Status__c = "SomeSubStatus";
       update record;
       return true;
   } catch (Exception cause) {
      throw AuraHandledExceptionFactory.create(cause);
   }
}

child button B JavaScript

handleButtonBClick() {
    updateAsStatusAndSubStatus({ recordId: this.recordId}).then(result => {
        if (result === true) {
            this.backToList();
        }
    }).catch(error => this.handleError(error));
}

child button B Apex

@AuraEnabled
public static Boolean updateAsStatusAndSubStatus(Id recordId) {
   try {
       Opportunity record = new Opportunity(Id = recordId);
       record.StageName = "SomeStageName";
       record.Sub_Status__c = null;
       update record;
       return true;
   } catch (Exception cause) {
      throw AuraHandledExceptionFactory.create(cause);
   }
}

Both buttons work, and the record is updated successfully.

Both buttons return a result of true;

Both buttons call the backToList JavaScript method

backToList() {
    this.dispatchEvent(new CustomEvent("back"));
}

The List only only refreshes correctly for button A.

I also have a refresh button on the list which calls refreshApex and no matter how many times I click on it, it does not get the refresh records.

I have to do a hard refresh of the page!

Question

  1. What is going wrong?
  2. How can I fix it such that refreshApex consistently works?
  3. What other ways are there to clear the cache such that wire will re-fire?
2
  • Dunno if it relates to your issue but note that wire functions are only invoked if the new data fetched from the server after a refreshApex has changed. Take a look at this answer for more info.
    – Phil W
    Commented Apr 8, 2020 at 11:45
  • I suspect this is what you're seeing. The solution is to switch to imperative invocation :D
    – Phil W
    Commented Apr 8, 2020 at 11:46

1 Answer 1

2

In my scenario, I was calling refreshApex which was calling an Apex method getRecords which returned a List<Opportunity>

But I was going from a record list size of 1 to 0 and my Apex method:

@AuraEnabled(cacheable=true)
public static List<Opportunity> getRecords() {

    List<Opportunity> records = [SELECT ... FROM Opportunity WHERE ...];

    if (records.size() == 0) {
        return null;
    }
    return records;
}

If there were no records, I was returning null which meant the lightning framework was not updating the cache.

When I changed the method to return an empty list it worked.

@AuraEnabled(cacheable=true)
public static List<Opportunity> getRecords() {

    List<Opportunity> records = [SELECT ... FROM Opportunity WHERE ...];

    if (records.size() == 0) {
        return new List<Opportunity>(); // <-- HERE
    }
    return records;
}

Which I guess can be further simplified down to:

@AuraEnabled(cacheable=true)
public static List<Opportunity> getRecords() {

    return [SELECT ... FROM Opportunity WHERE ...];
}
1
  • 2
    If you could accept this answer, it would mark it as solved, which would help keep the site nice and tidy.
    – Adrian Larson
    Commented Oct 15, 2022 at 1:21

You must log in to answer this question.

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