1

Is there any way to use refreshApex to refresh data passing from Parent to Child?

I have 2 components: Parent & Child. The parent will perform logic to make the data clean then pass to Child (list of records). The Child will use that public property (@api) to do some update.

Apex Controller

@AuraEnabled
public static List<Sobject> getDatas(Boolean isRecentlyView, 
                                         List<String> fields, 
                                         String sobjectType, 
                                         String query, 
                                         Integer limitNum){
    try {
        if (limitNum != null) {
            if (isRecentlyView) {
                query = 'SELECT ' + String.join(fields, ', ') + ' FROM ' + sobjectType + ' WHERE LastViewedDate !=null ORDER BY LastViewedDate DESC ';
                query += ' LIMIT :limitNum';
            } else {
                query = query.split('FROM')[1];
                query = 'SELECT ' + String.join(fields, ', ') + ' FROM ' +  query;
                query += ' LIMIT :limitNum';
            }
            System.debug(query);
            return Database.query(query);
        } else return new List<SObject>();
    } catch (Exception e) {
        throw e;
    }
}

Parent JS code

import getDatas from '@salesforce/apex/ParentController.getDatas';
import { LightningElement, api, track, wire } from 'lwc';
import {refreshApex} from '@salesforce/apex';

export default class ParentComponent extends LightningElement {

  datas = [];
  isRecentlyView = false;
  sObjectType = 'Account';
  numberOfRecords = '10';


  getData(){
  //do something to populate fields and query
    getDatas({
      isRecentlyView: _this.isRecentlyView,
      fields: fields, // passing fields here
      sobjectType: _this.sObjectType,
      query: query, // passing query here
      limitNum: _this.numberOfRecords})
      .then(result => {
        _this.datas = result;})
      .catch(e => {console.error(e);
      })
    }

Child JS code

@api datas;
@api objectApiName;
groupByValue = 'Type';
recordId = '';

handleListItemDrag(event){
    this.recordId = event.detail;
}

handleItemDrop(event){
    let status = event.detail;
    this.updateHandler(stage);
}

updateHandler(status){
    updateRecord({objectType : this.objectApiName,
                  recordId : this.recordId,
                  fieldApiName: this.groupByValue,
                  newValue: status})
    .then((result) => {
        if (result) 
            const evt = new ShowToastEvent({
                message: 'Record updated.',
                variant: 'success'
            });
        this.dispatchEvent(evt);
        refreshApex(this.datas);
    })
    .catch((error) => {
        console.log('Error save',error);
    })
}
  • Right now, I tried to call refreshApex inside Child component but it has not worked yet (above code)

  • I also tried to create a custom event and pass to Parent but it does not work too.

Parent HTML code

<template>
  <c-child-componet datas={datas} object-api-name={objectApiName}
    onupdaterecord={handleUpdateRecord}>
  </c-child-component>
</template>

Parent JS code

handleUpdateRecord(){
  refreshApex(this.datas);
}

Child JS code

updateHandler(status){
    updateRecord({ objectType : this.objectApiName,
                   recordId : this.recordId,
                   fieldApiName: this.groupByValue,
                   newValue: status})
    .then((result) => {
        if (result) 
            const evt = new ShowToastEvent({
                message: 'Record updated.',
                variant: 'success'});
        this.dispatchEvent(evt);
        const event = new CustomEvent('updaterecord');
        this.dispatchEvent(event);
    })
    .catch((error) => {
        console.log('Error save',error);
    })
}

Thank you so much

1 Answer 1

2

That's not how refreshApex works. It should be used only to refresh data provisioned via an Apex @wire since it needs the whole object returned by a wire adapted, not just the data property.

In your example you call the Apex method imperatively and Lightning Data Service doesn’t manage data provisioned by imperative Apex calls, so to refresh those data you have to call again getData() method.

Since the update should be triggered by a child component, it has to dispatch an event and the parent should handle it, as you already did, but instead of calling refreshApex, the parent should call getData().

Child JS

updateHandler(status){
    updateRecord({ objectType : this.objectApiName,
                   recordId : this.recordId,
                   fieldApiName: this.groupByValue,
                   newValue: status})
    .then((result) => {
        if (result)  {
            const evt = new ShowToastEvent({
                message: 'Record updated.',
                variant: 'success'
            });
            this.dispatchEvent(evt);
            const event = new CustomEvent('updaterecord');
            this.dispatchEvent(event);
        }
    })
    .catch((error) => {
        console.log('Error save',error);
    })
}

In the question's code you missed brackets after if (result), so this.dispatchEvent(evt); will dispatch nothing, since evt is block scoped and this.dispatchEvent(evt);` is outside the if block. I fixed it here.

Parent HTML code

<template>
  <c-child-componet datas={datas} object-api-name={objectApiName}
    onupdaterecord={handleUpdateRecord}>
  </c-child-component>
</template>

Parent JS code

getData(){
    //do something to populate fields and query
    getDatas({
        isRecentlyView: this.isRecentlyView,
        fields: fields, // passing fields here
        sobjectType: this.sObjectType,
        query: query, // passing query here
        limitNum: this.numberOfRecords
    })
        .then(result => {
            this.datas = result;
        })
        .catch(e => {
            console.error(e);
        })
}

handleUpdateRecord(){
  this.getData();
}

By the way, if you updare a record via Apex and you want to notify LDS that record data has changed so that it can take the appropriate actions to keep wire adapters updated (only them, it will not update data retrived from Apex) with the latest record data, you should use notifyRecordUpdateAvailable.

4
  • Hi @RubenDG, did you mean that I need to use notifyRecordUpdateAvailable to be able to refresh the data?
    – Pam
    Aug 20, 2023 at 14:46
  • @Pam no, in this case is not needed. Use it if you are in record page and update the record itself via apex. It was just a side note. The answer to original question, the TLDR is "call this.getData() instead of refreshApex in handleUpdateRecord method".
    – RubenDG
    Aug 20, 2023 at 16:06
  • Thank you! Because I tried to call this.getData() already but the data is the same. I think my code has other personal problem.
    – Pam
    Aug 21, 2023 at 6:46
  • @Pam Sometimes anonymize or simply alter the code before posting it here goes against yourself, because even the slightest change may hide (or fix) the error, especially if it's about Javascript, which is case-sensitive. The first thing to do when debugging, is identify which line throws an error or doesn't behave as expected. If the apex method is called once the child dispatch the event, but the data on child component is not updated, try to hide the component before calling apex and showing it only after the promise is handled.
    – RubenDG
    Aug 21, 2023 at 7:07

You must log in to answer this question.

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