0

An issue with the Apex controller / LWC interaction is that when retrieving values from an Apex controller / method the returned object will not bring back object properties that do not have values.

for example if we are trying to retrieve an Account from the database, we use @wire, call the apex method and within the Apex method utilize a query to retrieve necessary values.

return SELECT Id, Name, Occupation__c from Account LIMIT 1

the issue is that if Occupation__c is null in the database, then the field name "Occupation__c" is not even returned in the object passed back to the LWC. Which brings me to my question, how best to handle this in LWC?

currently I am using this method to "validate" the values coming back from the Apex method

 this.account = {
                AccountId: data.Id,
                OwnerId: data.OwnerId ? data.OwnerId : "",
                Occupation: data.Occupation__c ? data.Occupation__c : "",
                }

My Question is, is this a more efficient way to do this, is this best practice? does Salesforce have any examples to reference?

2 Answers 2

1

Well,

// account.js
import { LightningElement, wire, track } from 'lwc';

// Wire adapter to load records.
import { getRecord } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import ID_FIELD from '@salesforce/schema/Accoun.Id';
import OCUPATION_FIELD from '@salesforce/schema/Account.Occupation__c';

export default class AccountDetail extends LightningElement {
   // Id of Account to display.
   recordId;

   // Wire to object //
   @wire(getRecord, { recordId: '$recordId', fields: [NAME_FIELD, ID_FIELD, OCUPATION_FIELD] })
   account;

   get name() {
        return getFieldValue(this.account.data, NAME_FIELD);
   }

   get ocupation(){
        return getFieldValue(this.account.data, OCUPATION_FIELD);
   }

}

You can get more information here: https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_wire_adapters_record

The best approach if you still want to use the apex controler is save the data in an object and then resolve those using getters:

@wire(getMyAccount) wiredAccount({ data }) {
    if (data) {
        this.account = data;
    } 
}

get name() {
    return this.account && getSObjectValue(this.account, NAME_FIELD); }

More info here: https://developer.salesforce.com/docs/component-library/documentation/en/lwc/apex

3
  • I was asking about retrieving records through Apex, not LDS. LDS is limited as you need the record id (not always retrievable with "@api recordId" on community pages) and related lists can not be retrieved through it (as far as i know). I won't pose this as a question but rather a thought, with the removal of the "@track" decorator which makes all properties reactive, i've been limiting my getters as the component is refreshing so often. Maybe that is a flawed but having 10 or so getters seems ineffecient versus {account.name} in html
    – Bobbygllh
    Apr 27, 2020 at 17:25
  • Don't worry about the @track decorator since it will be removed soon, about it is ineffective, it doesn't seem that way to me, the logic should be solved as much as possible inside the js, that way it can be formatted, put default values, etc. if you have for example a field coming from apex and someone changes an api name, you would simply see the value empty, but if you have a getter with getSObjectValue and the reference to the field, no one can change an api name that is referenced in the js without fixing the references (that control doesn't work if the reference is in the HTML)
    – Pirata21
    Apr 27, 2020 at 20:00
  • I understand the value of utilizing the schema, I am more questioning the high number of getters that might be necessary with this structure, as well as the ability to use this structure with an html loop. And @track is already removed, that is what i said in my comment, so LWCs are rerendering more due to that change which is why i'm questioning a structure that would utilize a significant amount of getters, it doesnt seem complete yet. and i don't think access to objects should need to go build it in JS > HTML > back to JS
    – Bobbygllh
    Apr 28, 2020 at 14:30
1

JavaScript has some cool ways of dealing with this. The ternary operator is rarely used in JavaScript. You can use Object.assign, or you can use the || operator.

Or operator:

 this.account = {
            AccountId: data.Id,
            OwnerId: data.OwnerId || "",
            Occupation: data.Occupation__c || "",
            }

Returns the left-hand value or the right-hand value when "falsy".

Object.assign:

const defaultValues = { OwnerId: "", Occupation__c: "" };
this.account = Object.assign({}, data, defaultValues);

Properties are assigned from right to left, so any missing properties take on their default values.

Note that it doesn't usually matter if the property is omitted, as it would just normally be "undefined", which is a fasly value that you can use.

1
  • Yes, || operator is more effecient, should have been using that. However it is an issue if the property is ommitted as attempting to access the values of a related list causes an error (ie. initial relatedlist__r being undefined as well as potential properties)
    – Bobbygllh
    Apr 27, 2020 at 17:29

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.