1

I have a parent component that uses lightning data service (lds) to get the record. This record is then shared to all of it's children as needed using data binding. I need to update the record using apex because some fields users are only allowed to update when using an api. After I make the callout, update the record, and then reload lds, the field values I retrieved from the api do not display in my UI. I need to manually refresh the page to see it, which is a bad user experience. Is it possible to reload lds after using apex to update the record? Here is what I did in my code.

Parent.cmp

<aura:attribute name="prescription" type="Case" />
<aura:attribute name="patient" type="Contact" />
<aura:attribute name="user" type="User" />

<aura:method name="reload" action="{!c.reload}" />

<force:recordData aura:id="prescriptionEditor" 
                  recordId="{!v.recordId}" 
                  targetFields="{!v.prescription}"  
                  fields="Id,CoPayResult__c,AdditionalInsuranceMessage__c,Deductible_Remaining__c,Patient_Pay_Amount__c,Plan_Paid_Amount__c,RejectionCode__c,Verification_Errors__c"
                  mode="EDIT" 
                  recordUpdated="{!c.handlePrescription}" />

<force:recordData aura:id="patientEditor" 
                  recordId="{!v.prescription.Patient__c}" 
                  targetFields="{!v.patient}"
                  fields="Id,Email" 
                  mode="EDIT" recordUpdated="{!c.handlePatient}" />

<force:recordData aura:id="userEditor" 
                  recordId="{!v.userId}" 
                  targetFields="{!v.user}" 
                  layoutType="FULL" 
                  mode="EDIT"
                  recordUpdated="{!c.handleUser}" />



        <c:Child prescription="{!v.prescription}"  
                 parent="{! this }" />

ParentController.js

({ 
    handlePrescription: function(component, event, helper) {
        let prescription = component.get("v.prescription");
        let eventParams = event.getParams();
        //console.log(eventParams.changeType);
        if(eventParams.changeType === "ERROR") {
            helper.reload(component);
        } else if(eventParams.changeType === "LOADED") {            
            //console.log("Prescription has loaded successfully.");
            //console.log(JSON.parse(JSON.stringify(prescription)));

            component.set("v.userId", $A.get("$SObjectType.CurrentUser.Id"));

            let patient = component.get("v.patient");
            let user = component.get("v.user");

            if(patient == null && user == null) {
                setTimeout($A.getCallback(function () { component.find("patientEditor").reloadRecord() })); 
                setTimeout($A.getCallback(function () { component.find("userEditor").reloadRecord() }));                 
            }                  
        } else if(eventParams.changeType === "CHANGED") {
            helper.reload(component);
        } else if(eventParams.changeType === "REMOVED") {
            // record is deleted
            //console.log("Record was removed.");
        }
    },
    handlePatient: function (component, event, helper) {
        let prescription = component.get("v.prescription");
        let patient = component.get("v.patient");
        var eventParams = event.getParams();

        if (eventParams.changeType === "LOADED") {
            // record is loaded (render other component which needs record data value)
            //console.log("Patient has loaded successfully.");
            //console.log(JSON.parse(JSON.stringify(component.get("v.patient"))));
        }
        else if (eventParams.changeType === "CHANGED") {
            // record is changed
            //console.log("Record was changed.");
        } else if (eventParams.changeType === "REMOVED") {
            // record is deleted
            //console.log("Record was removed.");
        } else if (eventParams.changeType === "ERROR") {
            // there’s an error while loading, saving, or deleting the record
            //console.log("error.");
        }
    }, 
    handleUser: function (component, event, helper) {
        let user = component.get("v.user");
        let eventParams = event.getParams();

        if (eventParams.changeType === "LOADED") {
            //console.log("User has loaded successfully.");
            //console.log(JSON.parse(JSON.stringify(user)));
        }
        else if (eventParams.changeType === "CHANGED") {
            // record is changed
            //console.log("Record was changed.");

        } else if (eventParams.changeType === "REMOVED") {
            // record is deleted
            //console.log("Record was removed.");
        } else if (eventParams.changeType === "ERROR") {
            // there’s an error while loading, saving, or deleting the record
        }
    },    
    reload: function (component, event, helper) {
        helper.reload(component);
    }    
})

ParentHelper.js

reload : function(component) {
    setTimeout($A.getCallback(function () { 
        console.log('reloaded');
        component.find("prescriptionEditor").reloadRecord();
        component.find("patientEditor").reloadRecord();                                   
    })); 
}

Child.cmp

<aura:component>
    <aura:attribute name="parent" type="Aura.Component"/>    
    <aura:attribute name="prescription" type="Case" />

    <div class="slds-grid slds-wrap">
        <aura:if isTrue="{!!v.editing}">
            <!-- Save/Cancel buttons -->
            <div class="slds-grid slds-medium-size--3-of-3 slds-grid_align-end">
                <div class="slds-p-left_xx-small">                  
                    <c:GrandChild prescription="{#v.prescription}"
                                                   parent="{!v.parent}"/>
                </div>
                <div class="slds-p-left_xx-small">
                    <lightning:button variant="brand" 
                                      label="Edit" 
                                      onclick="{!c.toggleEditing}"/>
                </div>
            </div>
            <!-- Edit button -->
            <aura:set attribute="else">
                <div style="text-align:right;" class="slds-medium-size--3-of-3">
                    <lightning:button variant="brand" label="Save" onclick="{!c.save}" />                
                    <lightning:button variant="brand" label="Cancel" onclick="{!c.toggleEditing}" />
                </div>
            </aura:set>
        </aura:if>      
    </div>
</aura:component>

GrandChild.cmp

<aura:component implements="force:lightningQuickAction" controller="GrandChildController" >
    <aura:attribute name="parent" type="Aura.Component"/>    
    <aura:attribute name="prescription" type="Object"/>

    <button class="slds-button slds-button--brand" onclick="{!c.callHealthConnexxAndClose}">Verify</button>

</aura:component>

GrandChildController.js

({

callHealthConnexxAndClose : function(component, event, helper) 
{

    var action = component.get("c.getInsuranceVerification");

    action.setParams({caseId: component.get("v.prescription.Id") });

    action.setCallback(this, function(response) 
    {

        var state = response.getState();
        if (state === "SUCCESS") {

        } else if (state === "INCOMPLETE") {    

        } else if (state === "ERROR") {
            console.log("Failed with state: " + state);
            console.log(response.error[0].message);
        }       


        let p = component.get("v.parent");
        p.reload();   
    });

    $A.enqueueAction(action);
},

})

GrandChildController.apxc

public class GrandChildController {
    @AuraEnabled
    public static void getInsuranceVerification(Id caseId) {
        //System.debug('Received ' + caseIds.size() + ' Cases');

        List<Case> casesToUpdate = new List<Case>();
        Case c = [SELECT Id FROM Case WHERE Id = :caseIds]


            VerificationRequest req = new VerificationRequest(c);

            VerificationResponse response = sendVerRequest(req);

            if(response.calloutSuccess){
                if(response.Reply.Message != null) {
                    String message = 'Response from TripleFIN: ' + response.Reply.Message;
                    AuraHandledException auraError = new AuraHandledException(message);
                    auraError.setMessage(message);
                    throw auraError;                    
                }

                Case p = new Case();

                p.Id = c.Id;
                p.CoPayResult__c = response.Reply.CoPay;
                p.AdditionalInsuranceMessage__c = response.Reply.AdditionalInfo;
                p.Deductible_Remaining__c   = response.Reply.RemainingDeductableAmount;
                p.Patient_Pay_Amount__c = response.Reply.PatientPay;
                p.Plan_Paid_Amount__c   = response.Reply.TotalAmountPaid;
                String rejectCodeStr = '';
                for(RejectCodes rc : response.Reply.RejectCodes){
                    rejectCodeStr += String.ValueOf(rc.RejectCode) + '; ';
                }
                p.RejectionCode__c = rejectCodeStr;
                p.Verification_Errors__c = response.Reply.Errors != null ? String.valueOf(response.Reply.Errors) : null;

                try {
                    update p;
                } catch (DMLException e) {
                    String message = e.getMessage();
                    AuraHandledException auraError = new AuraHandledException(message);
                    auraError.setMessage(message);
                    throw auraError;                        
                }
            }

} }

I know this code is working, because when I refresh my UI, the values are there that are pulled in GrandChildController.apxc. The problem appears to be when I'm calling reload() from within GrandChild.cmp

  • Are you getting any error in console while calling aura:method reload from grandchildren? – Pranay Jaiswal Feb 5 '19 at 20:26
6

What I feel here is in force:recordData the reloadRecord method when called is not doing a server round-trip to fetch new values. It's displaying the stale value from local cache.

From SF docs of reloadRecord method

Performs the same load function as on init, using current config values (recordId, layoutType, mode, etc) but does not force a server trip if not required

Somehow SF feels that its best to fetch values from local cache, You have to override this behavior by passing a boolean parameter(skipCache) to reloadRecord method which will force a server roundtrip to get the latest value from the database.

Thus your Parent Helper code will be

reload : function(component) {
    setTimeout($A.getCallback(function () { 
        console.log('reloaded');
        component.find("prescriptionEditor").reloadRecord(true);
        component.find("patientEditor").reloadRecord(true);                                   
    })); 
}

Src: https://developer.salesforce.com/docs/component-library/bundle/force:recordData/specification

| improve this answer | |
  • Amazing how simple that solution was. Thanks! I'm curious why they don't round-trip every time... – Tyler Zika Feb 5 '19 at 21:33
  • @TylerZika fetching value from server is very resource intensive. Sf tries to avoid that if it feels that local and sever values are same. They have certain set of algorithm to determine if it should use local cache or get from server. Now it works fine if the dml happened in same parent component. The components could track it. In your case the dml is happening in 2 level hierarchy by grandchildren that it makes harder for parents to determine if there was a change. – Pranay Jaiswal Feb 5 '19 at 23:19
0

Try this:

Parent.cmp (Add a boolean, using that, recreate the child component)

    <aura:attribute name="reload_child" type="Boolean" />

     <aura:if isTrue="{!v.reload_child}">
        <c:Child prescription="{!v.prescription}"  
             parent="{! this }" />
      </aura:if> 

ParentHelper.js

reload : function(component) {
setTimeout($A.getCallback(function () { 
    console.log('reloaded');
    component.find("prescriptionEditor").reloadRecord();
    component.find("patientEditor").reloadRecord();  
    *component.set("v.reload_child", false); 
    component.set("v.reload_child", true);*                                 
})); 

}

We can dig deep and solve it with rerender, but I like it dirty.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.