7

We are working on building a list view where you can perform New, Edit and mass update of records. We are using the lightning:recordEditForm for the New and Edit view.

The issue we are facing is whenever you edit a record via lightning:recordEditForm and if the same record is selected and changed as part of a mass update, opening the edit view of the same record populates the order value instead of showing the new values of the field updated by mass action.

Steps:

1) Load all the contact records in a list view (we are using lightning:datatable)

2) Click on the Edit button on a record, for instance Jane and update her's Phone number using lightning:recordEditForm

3) Select Jane and other few contacts, mass update their Phone to '121312' via apex controller action.

4) Listview refresh and edit the Jane again, you'll see the old phone number value.

NOTE: I get this weird error when I try to destroy the lightning:recordEditForm after updating the record. I get the below error:

[Error in $A.getCallback() [Cannot read property 'querySelectorAll' of null]]

Tried wrapping the lightning:recordEditForm inside a div and conditionally show it instead of aura:if, I don't get the error but still old value issue exists.

I believe the records cached by internal Lightning Data Service(LDS) in the lightning:recordEditForm is unaware of the record change, so it populates whats in the cache.

Is there's a way to force the lightning:recordEditForm get the correct record values?

Code:

ApexController:

public class ContactListController {
    @AuraEnabled
    public static List<Contact> getContact() {
        return [SELECT Id, Name,FirstName,LastName, Phone, Email FROM Contact];
    }

    @AuraEnabled
    public static List<Contact> updateContacts(String contactstr) {
        List<Contact> con = (List<Contact>) JSON.deserialize(contactstr, List<Contact>.class);
        system.debug('con::'+con);
        update con;
        return getContact();
    }
}

Markup:

<aura:application controller="ContactListController" extends="force:slds">

    <aura:attribute name="mydata" type="Object"/>
    <aura:attribute name="mycolumns" type="List"/>
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>
    <aura:attribute name="selectedRecord" type="Contact" default= "{'sobjectType' : 'Contact'}"/>
    <aura:attribute name="selectedRecords" type="Contact[]" default= "[]"/>

    <aura:if isTrue="{!v.selectedRecord.Id}">
        <lightning:recordEditForm objectApiName="Contact" recordId="{!v.selectedRecord.Id}" onsuccess="{!c.refreshRecord}">
            <lightning:inputField fieldName="Name" />
            <lightning:inputField fieldName="Email" />
            <lightning:inputField fieldName="Phone" />
            <lightning:button type="button"  name="cancel" label="cancel" onclick="{!c.cancel}"/>

            <lightning:button type="submit"  name="update" label="Update"/>

        </lightning:recordEditForm>
    </aura:if>

    <lightning:button type="button"  name="update phone" label="Update phone to 121312" onclick="{!c.updateSelectedRecords}"/>
    <lightning:datatable aura:id="table" data="{! v.mydata }" 
                         columns="{! v.mycolumns }" 
                         keyField="Id"
                         onrowaction="{! c.editRecord }"
                         onrowselection="{! c.recordSelection }"                         
                         />
</aura:application>

Controller.js:

({
    init: function (cmp, event, helper) {
        var actions = [
            { label: 'Edit', name: 'edit' }
        ];
        cmp.set('v.mycolumns', [
            {label: 'Name', fieldName: 'Name', type: 'text'},
            {label: 'Contact Email', fieldName: 'Email', type: 'email'},
            {label: 'Contact Phone', fieldName: 'Phone', type: 'phone'},
            { type: 'action', typeAttributes: { rowActions: actions } }
        ]);

        helper.getRecords(cmp);
    },
    editRecord : function (cmp, event) {
        var action = event.getParam('action');
        var row = event.getParam('row');
        console.log(row);
        cmp.set("v.selectedRecord", row);
    },
    cancel : function (cmp, event, helper) {
        cmp.set("v.selectedRecord", {'sobjectType' : 'Contact'});
        cmp.find("table").set("v.selectedRows", []);
    },
    refreshRecord : function (cmp, event, helper) {
        var response = event.getParam('response');
        console.log(response);
        helper.getRecords(cmp);
        cmp.set("v.selectedRecord", {'sobjectType' : 'Contact'});
    },
    recordSelection : function (cmp, event) {
        cmp.set('v.selectedRecords', event.getParam('selectedRows'));
        console.log(event.getParam('selectedRows'));
    },
    updateSelectedRecords : function (cmp, event) {
        var selectedRows = cmp.get('v.selectedRecords');

        selectedRows.map(function(record) {
            record.Phone = '121312';
        });

        var contactstr = JSON.stringify(selectedRows);

        var action = cmp.get("c.updateContacts");
        action.setParams({
            "contactstr" : contactstr
        });
        action.setCallback(this, function(resp) {
            console.log(resp.getState() );
            if (resp.getState() == 'SUCCESS') {
                cmp.set('v.mydata', resp.getReturnValue());
                cmp.set('v.selectedRecords', []);
            }
        }) ;

        $A.enqueueAction(action);
    }
})

Helper.js:

({
    getRecords : function(cmp) {

     var action = cmp.get("c.getContact");
        action.setCallback(this, function(resp) {
            if (resp.getState() == 'SUCCESS') {
                 cmp.set('v.mydata', resp.getReturnValue());
            }
        }) ;

        $A.enqueueAction(action);
    }
})
3

As per LDS Considerations:

Lightning Data Service shared data storage provides notifications to all components that use a record whenever a component changes that record. It doesn’t notify components if that record is changed on the server, for example, if someone else modifies it. Records changed on the server aren’t updated locally until they’re reloaded.

So you might need to reload the components. Not the perfect solution but will work.

  • Can you explain reloading the component part. Are you implying to destroy and re-create the component again? – Praveen Apr 24 '18 at 11:07
  • @Praveen yes you can give that a try or try to reload the page if possible. – Tushar Sharma Apr 24 '18 at 12:18
  • Recreating the component did not solve the issue. Reloading the page is not an option for us because the component will live in LEX container. – Praveen Apr 24 '18 at 12:39
  • @Praveen As of now I can't think of any other solution. – Tushar Sharma Apr 24 '18 at 12:48
  • Any workaround for this apart from reloading the page, did SF gave any solution ?? – sfdeveloper Sep 4 '18 at 11:50
1

We faced the same problem 3 months ago. We logged a case to Salesforce. They answered -

This issue seems like there doesn't seem to be a way to work around this caching of the recordEditForm. In your implementation when updating through the lightning data table this is then calling a server-side action to save the components, this then prevents the lightning data service to be notified of changes to the record. https://developer.salesforce.com/docs/atlas.en-us.212.0.lightning.meta/lightning/data_service_considerations.htm

It doesn’t notify components if that record is changed on the server, for example, if someone else modifies it. Records changed on the server aren’t updated locally until they’re reloaded. Lightning Data Service notifies listeners about data changes only if the changed fields are the same as in the listener’s fields or layout.

Observing the behaviour in your org, it seems after a few seconds the cache becomes invalidated and a new retrieve is executed.

So we took an alternative way to solve this.

We added another button in the form.

Component:

<lightning:button aura:id="refresh" variant="brand" type="button" label="Refresh" title="Refresh" onclick="{!c.handleRefresh}"/>

Controller: Here: WMS_LastModifiedByAura__c (Text, 40) is just a field that is updated through the edit form.

handleRefresh: function(cmp, event, helper) {
cmp.set("v.showSpinner", true);
cmp.set("v.buttonPressed", "refresh");
  if(cmp.get("v.buttonPressed") === "refresh") {
     var eventFields = {};
     var today = new Date();
     var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
     eventFields["WMS_LastModifiedByAura__c"] = date;
     cmp.find('recordData').submit(eventFields);
  }
},  

handleSuccess: function(cmp, event, helper) {
  cmp.set("v.showSpinnerChild", false);
  var record = event.getParam("response");
  if(cmp.get("v.buttonPressed") != "refresh") {
    helper.showToast(event, 'The claim line item has been updated.', 'success', 'dismissible', record);
    helper.disableVisibility(cmp, event, true); 
 } else {
    helper.showToast(event, 'The record has been refreshed.', 'success', 'dismissible', null);
 }
}

So what happens now is when User clicks the refresh button, it updates a field value which tells the data service that cache needs to be updated.

0

I tried something like this:-

lightning:recordEditForm onload={!c.Onload}

controller

Onload: function(component, event, helper) {
    $A.get('e.force:refreshView').fire();
},
  • Not meaning to be snarky, but when you say tried...did it work? – Girbot Oct 30 '18 at 13:15
  • Yep, it worked for me !! – Sunil Reddy Oct 31 '18 at 7:04
  • Did it work inside a standalone app? – Praveen Nov 8 '18 at 17:35
  • 1
    that causes an infinite loop. – Cloxure Dec 21 '18 at 13:14

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.