LWC – Problem Replacing if:true with lwc:if

javascriptlightning-web-componentsspring23

This release note states that if:true directives must be replaced with lwc:if.

However, I noticed that in the LWC I am working on, this is not as easy as it sounds. Just doing a simple textual substitution causes the LWC to stop functioning.

Probably because of this feature:

With the lwc:if, lwc:elseif, and lwc:else conditional directives, the
property getters are accessed only one time per instance of the
directive.

But this LWC has a lot of asynchronous interaction with Apex. When the LWC pops up, not all data is available yet, it may take seconds before it becomes available. In the old situation, that was not a problem: the sections that used the data from Apex were guarded by if:true directives. As soon as data became available, the LWC was updated automatically.

<template lwc:if={accRecord}>
    &nbsp;&lpar;{accName}&rpar;
</template>

accRecord is a JavaScript field that gets its value from an Apex method:

import getAccount from '@salesforce/apex/OpportunityForLWCController.getAccount';
...
accRecord;
...
getAccountRecord() {
    if (this.accId && ! this.accRecord) {
        getAccount( { accId: this.accId } )
        .then(result => {
            this.accRecord = result ? result : undefined;
        })
        .catch(error => {
            this.showNonFatalError(this.errorMsgFromSF(error));
        });
    }
}
...
get accName() { return this.accRecord.Name; }

But with lwc:if, this no longer works. The condition is only evaluated once and the data from Apex will not be immediately available. The LWC will display, but mostly blank. It is not updated when data arrives from Apex. The LWC is broken.

How to solve this? The Salesforce documentation on lwc:if does not deal with this situation.

Update: the LWC is used in several places. It can be invoked on an Account page and on an Opportunity page. The test above was done on the Opportunity page. I have just tested it on an Account page, and to my surprise, the Account record data is collected. The next step for the LWC is to create or retrieve an Opportunity. And here I get the same behaviour as before: the LWC just stops processing.

This is consistently so: everytime I invoke the LWC on the Account page, the Account data can be retrieved, but the Opportunity data is not created/retrieved. On the Opportunity page, the Account data cannot be retrieved.

After adding console.log statements, I can see that the Apex methods are being called. But somehow, the if:true never re-evaluates the condition. I see an Uncaught (in promise) error in the console log, but it doesn't help me: lots of aura_prod.js lines, but nothing that I can trace to my LWC.

If I use if:true, the LWC works, if I replace if:true with lwc:if (and nothing more), I get the behavior I have described. Also: the error does not occur in the if:true situation! Just replacing it with lwc:if triggers that error.

Summarizing: it looks like replacing if:true with lwc:if causes the second time an Apex method is called (it doesn't matter which) to – somehow – cause an Uncaught (in promise) error. In my first scenario, Apex method A is called, then B. B causes the promise error. In my second scenario, Apex method B is called, then A. A causes the promise error. After restoring the if:true, no errors occur anymore.

I have checked the Apex debug logs: they do not contain any errors, I can see that they collect the data that will be used in the Javascript code.

Best Answer

My HTML page contained 11 if:true tags and 1 if:false. After replacing all of these one by one, I found out that the problem was with the if:false.

What I had:

<template if:false={oppCreatedFromEmail}>

What I replaced it with:

<template lwc:if={oppNotCreatedFromEmail}>

Using this new getter function:

get oppNotCreatedFromEmail() { return ! this.oppCreatedFromEmail(); }

But this is not correct! JavaScript is in this regards not like other languages. Simply negating an expression can lead to unexpected results, as we see here. This has to do with differences between undefined and null.

So when I had this proper definition for oppNotCreatedFromEmail, my LWC worked again:

return typeof this.oppRecord.Opp_per_mail__c === 'undefined' ||
       this.oppRecord.Opp_per_mail__c === null
Related Topic