2

I am using a Custom LWC on the record page of my Custom Object. In my LWC I have a wired list of Related Records which I am using in a datatable. I have a Screen Flow on the record page makes a call to Quickbooks and updates the parent Invoice and upserts the Invoice lines.
When the Flow runs the updates to the parent fields are visible on the screen however the related records in my datatable are not refreshing.
I added a button to call refreshApex so I can manually refresh the wired list.

Is there a way I can detect when the parent is updated and run the refresh automatically? I tried using a connectedCallback and a renderedCallback, but these were not fired when the parent is updated.

import {LightningElement, api, wire} from 'lwc';
import getInvoiceLineList from '@salesforce/apex/Invoice_RecordPage_Helper.getInvoiceLines';
import {refreshApex} from '@salesforce/apex';

import {getRecord, getFieldValue, getFieldDisplayValue, updateRecord} from 'lightning/uiRecordApi';
import field_SyncToken from '@salesforce/schema/Invoice__c.SyncToken__c';

const importFields = [
  field_SyncToken
];

export default class Invoice_RecordPage extends LightningElement {
  @api recordId;

  @wire(getRecord, { recordId: '$recordId', fields: importFields}) invoice;
  
  invoiceLineColumns = [
    {label: 'Line', fieldName: 'LineNumber__c', initialWidth: 75},
    {label: 'Product/Service', fieldName: 'ProductName'},
    {label: 'Description', fieldName: 'ProductDescription'},
    {label: 'Net Amount', fieldName: 'NetAmount__c', type: 'currency'}
  ];

  invoiceLineWiredList;
  invoiceLineData = [];
  @wire(getInvoiceLineList, {
    invoiceId: '$recordId'
  })
  wiredInvoiceLines(invlResponse){
    this.invoiceLineWiredList = invlResponse;
    if(invlResponse.data){
      let tempList = [];
      invlResponse.data.forEach((record) => {
          let r = Object.assign({}, record);  
            r.ProductName = r.InvoiceProduct__r?.Name;
            r.ProductDescription = r.InvoiceProduct__r?.Description__c;
          tempList.push(r);            
      });
      this.invoiceLineData = tempList;
        console.table(this.invoiceLineData);
    }else{
      console.log('Error = ' + JSON.stringify(invlResponse.error));
    }
  }

  handleRefresh(){
    refreshApex(this.invoiceLineWiredList);
  }
}
2
  • Just a question: The Flow doesn't update Invoice__c.SyncToken__c and the @wire for the Invoice is not called after an update by the Flow, right? (Otherwise you could possibly plug in the Invoice Lines as a parent-to-child subquery and have only one wire.) Oct 27, 2023 at 21:40
  • Basically the flow performs a callout to Quickbooks and updates the Invoice and upserts the Invoice Lines. One of the field updated is the Sync Token. Oct 27, 2023 at 21:51

1 Answer 1

0

I assume the Lightning page shows the Invoice__c.SyncToken__c as such, whereas the mark-up of the LWC does not output the invoice.SyncToken__c - because the invoice gets as stale as the invoiceLineData.

There are two problems here:

  • There is no native way the LWC is informed of the data change. My suggestion is to use a Platform Event, publish it with the Flow and listen to it via the empApi.

  • @wire is by definition cached, which conflicts with the need to get up-to-date data. In addition to that (at least based on the code you provide) retrieving invoice and its child records makes two server calls, where one suffices. My suggestion: a dedicated Apex call that can be used repetitively in a simple way, making use of parent-to-child subquery.

The LWC would then look somewhat like this:

import {LightningElement, api} from 'lwc';
import getInvoice from '@salesforce/apex/Invoice_RecordPage_Helper.getInvoice';
import {subscribe} from 'lightning/empApi';
import {getFieldValue, getFieldDisplayValue, updateRecord} from 'lightning/uiRecordApi';


export default class Invoice_RecordPage extends LightningElement {
  @api recordId;

  invoiceLineColumns = [
    {label: 'Line', fieldName: 'LineNumber__c', initialWidth: 75},
    {label: 'Product/Service', fieldName: 'ProductName'},
    {label: 'Description', fieldName: 'ProductDescription'},
    {label: 'Net Amount', fieldName: 'NetAmount__c', type: 'currency'}
  ];

  invoice;
  invoiceLineData = [];

  subscription = {};

  async connectedCallback() {

      const self = this;
      const messageCallback = function(response) {
          self.doGetInvoice();
      }

      subscribe('/event/InvoiceLineRecordsChange__e', 
        -1, messageCallback).then((response) => {
          this.subscription = response;
      });

      this.doGetInvoice();
  }

  async doGetInvoice() {
    this.invoice = await getInvoice({ invoiceId: this.recordId }); 
    this.invoiceLineData = this.getInvoiceLineData(this.invoice?.InvoiceLines__r);
  }

  getInvoiceLineData(invoiceLines){
    let tempList = [];
    invoiceLines.forEach((record) => {
        let r = Object.assign({}, record);  
          r.ProductName = r.InvoiceProduct__r?.Name;
          r.ProductDescription = r.InvoiceProduct__r?.Description__c;
        tempList.push(r);            
    });
    return tempList;
  }
}

If many invoices are added by many people at the time of viewing the Invoice page, a recordId filter could be added, based on an event that states the Invoice ID.

This workaround makes use of Platform Events. Platform Events come with a number of limitiations, and they might not always emit immediately. But in the absence of anything better, this might be the best option available.

1
  • 1
    thanks @felix - this was helpful! Oct 31, 2023 at 16:03

You must log in to answer this question.

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