1

I have a component that drops into a record page sidebar (Lead or Contact). It uses LDS to pull data for the record, including the MobilePhone field.

I'm noticing that if the MobilePhone field is not part of the record layout, it doesn't appear in the LDS data -- even if I specify it in the force:recordData fields. If I call for the data via an Apex handler, it can access the data in the field, just can't get it via LDS.

Here's the code, which specifies FULL layoutType, which I would assume gives me access to everything, but maybe it's only everything that's on a layout. But if you have multiple layouts for an object, which layout?

<force:recordData aura:id="recordLoader"
  recordId="{!v.recordId}"
  layoutType="FULL"
  targetRecord="{!v.record}"
  fields="{!v.recordFields}"
  targetFields="{!v.simpleRecord}"
  targetError="{!v.recordError}"
  recordUpdated="{!c.handleRecordUpdated}"
  />

I can't find any documentation that mentions the fact that a field has to be in the layout.

Looking for confirmation/documentation.

Here's my controller. In the doInit, I set the recordFields specified in the LDS. The missing data is in the handleRecordUpdated() method, where I try to access the Lead.MobilePhone field -- it's coming up null, dropping to the else and giving me an error message.

 doInit : function(component, event, helper)
    {
        // console.log('NewConversationController requireOptIn: ' + component.get("v.requireOptIn"));
        var recordId = component.get("v.recordId");
        if (recordId != null)
        {
            if (recordId.indexOf('003') == 0)
            {
            component.set("v.recordFields", "Name, FirstName, AccountId, MobilePhone");            
            } 
            else if (recordId.indexOf('00Q' == 0))
            {
            component.set("v.recordFields", "Name, FirstName, MobilePhone");
            } 
        }
        helper.getNumbers(component, event, helper);
    },


    handleRecordUpdated : function(component, event, helper)
    {
        var recordId = component.get("v.recordId");
        if (recordId.indexOf('003') == 0)
        {
            // console.log("🦊 Contact" + JSON.stringify(component.get("v.simpleRecord")));
            var Contact = component.get("v.simpleRecord");
            if (Contact.MobilePhone != null)
            {
                component.set("v.Contact", Contact);        
                var Contacts = component.get("v.Contacts");
                Contacts.push(Contact);
                component.set("v.Contacts", Contacts);
                component.set("v.To", Contact.Name);
                component.set("v.ToIcon", "standard:contact");
                component.set("v.FirstName", Contact.FirstName);
                component.set("v.AccountId", Contact.AccountId);
                component.set("v.NeedRecipient", false);
            } else{
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    "type": "warning",
                    "mode": "dismissable",
                    "duration": 3000,
                    "message": "No mobile phone number for " + Contact.Name + "."
                });
                toastEvent.fire();
            }

        } else if (recordId.indexOf('00Q') == 0)
        {
            // console.log("🦋 Lead: " + JSON.stringify(component.get("v.simpleRecord")));
            var Lead = component.get("v.simpleRecord");
            if (Lead.MobilePhone != null)
            {
                component.set("v.Lead", Lead);
                var Leads = component.get("v.Leads");
                Leads.push(Lead);
                component.set("v.Leads", Leads);
                component.set("v.To", Lead.Name);
                component.set("v.ToIcon", "standard:lead");
                component.set("v.FirstName", Lead.FirstName);
                component.set("v.NeedRecipient", false);
            } else {
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    "type": "warning",
                    "mode": "dismissable",
                    "duration": 3000,
                    "message": "No mobile phone number for " + Lead.Name + "."
                });
                toastEvent.fire();
            }
        } 

    },
1

layoutType="FULL" will fetch the default layout assigned to that user. From LDS Docs, when you specify fields (included/excluded from default page layout), they are also loaded.

The issue (I would rather say the bug in documentation):

  1. fields attribute will not trigger the reload of record. So, it is better to use conditional rendering. Reason: When record is initially loaded, the fields is not yet set by doInit method and when the fields are set, the recordData will not reload the record. Ofcourse you can use reloadRecord() but its not required as you need extra fields. So, if you use conditional rendering (When fields!=null), the recordData will load ONLY after the fields are set .
  2. Although documentation shows fields attribute as String, it is actually a List .

Below is the sample working code with respect to above points:

COMPONENT:

<aura:attribute name="recordFields" type="List" default="[]"  />
<aura:attribute name="accountRecord" type="Object"/>
<aura:attribute name="recordLoadError" type="String"/>

<aura:handler name="init" value="{! this }" action="{! c.init }"/>

<div class="slds-theme_default slds-box">
    <aura:if isTrue="{!not(empty(v.recordFields))}">
        <force:recordData aura:id="recordLoader"
                          recordId="00128000009j45uAAA"
                          layoutType="FULL"
                          fields="{!v.recordFields}"
                          targetFields="{!v.accountRecord}"
                          targetError="{!v.recordLoadError}"
                          />

        Name - {!v.accountRecord.Name}, Active - {!v.accountRecord.Active__c}
    </aura:if>
</div>

CONTROLLER JS:

init : function(component, event, helper){
    component.set("v.recordFields",['Name','Type','Phone','Active__c','Description']);
},

Note that List has to be set on fields.

| improve this answer | |
  • THANK YOU! That fixed it. – PatMcClellan__c Aug 26 '19 at 17:59
  • Can you elaborate on the first point above: conditional rendering to force reload of the record? – PatMcClellan__c Aug 26 '19 at 18:19
  • added in answer – salesforce-sas Aug 26 '19 at 18:32
0

Please look here: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/data_service_load_record.htm

It states:

To get a field from an object regardless of whether an admin has included it in a layout, use the fields attribute and request the field by name. To guarantee that a field is always there for the component, specify the field in addition to getting all the fields on a layout.

| improve this answer | |
  • Thanks, Rodrigo. However, I am specifying the field name in the v.recordFields, and it's not returning it. – PatMcClellan__c Aug 26 '19 at 17:20
  • What is the FLS for the field? Is it happening for all users/profiles? Have you tried to eliminate the layoutType and just leave the fields you would like to see? – Rodrigo Aug 26 '19 at 17:23
  • I checked FLS and it's visible and editable for all. I'm specifying the field, then trying to retrieve the data from v.simpleRecord (targetFields). Should be there, but just isn't. I did a console.log( JSON.stringify(component.get("v.simpleRecord"))) and the field just isn't there -- not null, missing. – PatMcClellan__c Aug 26 '19 at 17:27
  • post your controller here too.... – Rodrigo Aug 26 '19 at 17:28
  • Added the controller code to the original post above. BTW, sorry this is aura -- I wrote this over a year ago. – PatMcClellan__c Aug 26 '19 at 17:33
0

Thanks @salesforce-sas. Your post got me started on a fix. I did have to change targetFields to a list, but the conditional rendering didn't work for me. Here's what I did instead.

I added a boolean attribute to the component: reloadedRecord="false". Then, I added a reload checker at the top of my handleRecordUpdated handler. That way, if the record loads without a MobilePhone field, it reloads and sets the reloadedRecord flag to true so it only reloads once. After that, a null value on the MobilePhone field will still generate an error as it should.

 handleRecordUpdated : function(component, event, helper)
    {
        if(component.get("v.simpleRecord").MobilePhone == null && !component.get("v.reloadedRecord")){
            component.set("v.reloadedRecord", true);
            component.find('recordLoader').reloadRecord(true);
        }else{

            var recordId = component.get("v.recordId");
            if (recordId.indexOf('003') == 0)
            {
                // console.log("🦊 Contact" + JSON.stringify(component.get("v.simpleRecord")));
                var Contact = component.get("v.simpleRecord");
                if (Contact.MobilePhone != null)
                {
                    component.set("v.Contact", Contact);        
                    var Contacts = component.get("v.Contacts");
                    Contacts.push(Contact);
                    component.set("v.Contacts", Contacts);
                    component.set("v.To", Contact.Name);
                    component.set("v.ToIcon", "standard:contact");
                    component.set("v.FirstName", Contact.FirstName);
                    component.set("v.AccountId", Contact.AccountId);
                    component.set("v.NeedRecipient", false);
                } else{
                    var toastEvent = $A.get("e.force:showToast");
                    toastEvent.setParams({
                        "type": "warning",
                        "mode": "dismissable",
                        "duration": 3000,
                        "message": "No mobile phone number for " + Contact.Name + "."
                    });
                    toastEvent.fire();
                }

            } else if (recordId.indexOf('00Q') == 0)
            {
                console.log("🦋 Lead: " + JSON.stringify(component.get("v.simpleRecord")));
                var Lead = component.get("v.simpleRecord");
                if (Lead.MobilePhone != null)
                {
                    component.set("v.Lead", Lead);
                    var Leads = component.get("v.Leads");
                    Leads.push(Lead);
                    component.set("v.Leads", Leads);
                    component.set("v.To", Lead.Name);
                    component.set("v.ToIcon", "standard:lead");
                    component.set("v.FirstName", Lead.FirstName);
                    component.set("v.NeedRecipient", false);
                } else {
                    var toastEvent = $A.get("e.force:showToast");
                    toastEvent.setParams({
                        "type": "warning",
                        "mode": "dismissable",
                        "duration": 3000,
                        "message": "No mobile phone number for " + Lead.Name + "."
                    });
                    toastEvent.fire();
                }
            } 
        }
    },
| 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.