6

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.

10
  • 5
    lwc:if evaluates once per render cycle, not once ever. As a trivial example, I can create blinking text, which wouldn't be possible if the value were only evaluated once. Can you provide a concrete example that we can use to replicate the problem?
    – sfdcfox
    Feb 22 at 10:46
  • @sfdcfox I have added the relevant piece of the HTML code. It's really simple. In the full code it's surrounded by a template and a bunch of div directives, but none of them have any conditions or rendered directives, only CSS class directives. Feb 22 at 12:05
  • 1
    I have tried lwc:if at my end, with the condition you mentioned, it works for me. But as you said there is a delay in response and lwc:if it is rendered, there is one suggestion I can give to wrap the component in a boolean variable which will be set to true once all the required data is loaded. I suggest you share the js code, so we can see how you are handling the asynchronous method. Mar 4 at 11:42
  • 1
    @SanderdeJong accRecord seems to be an object? Could you confirm whether its decorated with @track in your actual code? Or could you try using a simple boolean property instead of object in your code? The salesforce documentation for lwc:if (although doesn't state anything explicitly) shows examples with boolean properties only. This is just a suggestion to check if uncaught promise exception you have observed is due to minor bug in the framework code.
    – arut
    Mar 19 at 10:08
  • 1
    Good suggestion arut, thanks! I have added @track to all the attributes. Unfortunately, no difference. Still getting that "Uncaught (in promise)" error. Mar 20 at 7:31

1 Answer 1

1

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .