12

I am having a situation where I'm trying to pop an alert on an opportunity, but it's conditional based on data on the current user, and data on a custom object.

I noticed that on refreshes the alert doesn't pop consistently.

Original Approach: Produced Inconsistent Results

The idea is that the user has data used for a second server call. So I had chained together 3 components.

Parent Component - Get User Data @wire decorator to fire aura enabled apex method 
 |_ Child Component 1 - Check SF for specific record that has user data on it. @wire decorator to fire aura enabled apex method  
      |___Child Component 2 - Fire Alert if Child Component returns data 

However, Parent component fires every time, but the second Child does not fire consistently.

So my thought was to try promises.

New Approach: Trying Promises

I decided I would use the connectedCallBack() function to attempt to control the server side calls.

Essentially, server side call to get user; if user is found, fire second server side call, and then begin logic on child components. Problem: I can't get the second promise to fire in this setup. I'm sure it's a syntax issue.

HTML - Parent

<template>

    <template if:true={userObj.ctmUserId}>
        <c-opp-contact-phone-alert
            ctm-user-id={userObj.ctmUserId}
            record-id={recordId}
        >
        </c-opp-contact-phone-alert>
    </template>

</template>

JS - Parent

connectedCallback(){
        console.log('CONNECTED CALLBACK');
        getCurrentUser({userId: USER_ID}).then(result => {
            console.log('IN PROMISE: USER');
            this.userObj.ctmUserId = result.CTM_Agent_Id__c;
            return lookupExistingPhone({curUserCtmId: this.userObj.ctmUserId})

        }).then((result) => {
            console.log('IN LOOKUP PROMISE');
            this.ctmRecord = result;
            console.log(this.ctmRecord);
        })
    }

1 Answer 1

12

There's a much easier way to do this in LWC:

async connectedCallback() {
  this.userObj.ctmUserId = await getCurrentUser({userId: USER_ID}).CTM_Agent_Id__c;
  this.ctmRecord = await lookupExistingPhone({curUserCtmId: this.userObj.ctmUserId});
}

This allows you to wait asynchronously automatically without all the complicated setup.

You can read more about async/await on MDN.

I wrote a demo component that calls two methods in a row, both by async/await and promise chains.

public with sharing class q310887 {
  @AuraEnabled
  public static String method1() {
    return 'Hello';
  }
  @AuraEnabled
  public static String method2(String param) {
    return param + ' World';
  }
}

<template>
  <div>
    {output}
  </div>
  <lightning-button onclick={asyncCall} label="Async/Await">
  </lightning-button>
  <lightning-button onclick={promiseCall} label="Promise Chain">
  </lightning-button>
</template>

import { LightningElement } from "lwc";
import method1 from "@salesforce/apex/Q310887.method1";
import method2 from "@salesforce/apex/Q310887.method2";

export default class Q310887 extends LightningElement {
  output = "Waiting...";
  connectedCallback() {}
  async asyncCall(event) {
    this.output = "Waiting...";
    this.output = await method1();
    this.output = await method2({ param: this.output });
  }
  promiseCall(event) {
    this.output = "Waiting...";
    method1()
      .then((result) => ((this.output = result), method2({ param: result })))
      .then((result) => (this.output = result));
  }
}

I also tested this in IE 11, and both methods also work. There should be no problem using either technique in the code. One small explanation is in order here.

When you use (...) => expr, the result of the expression is returned back. I use this to return the value of the next promise to continue the chain. The , operator performs each action (typically assignment), and discards all but the last result. I use this to assign the value from the first method before passing it to the next. Note that the "extra" parentheses are actually necessary because of the operator precedence of ,; without it, JavaScript presumes that the comma is introducing a new parameter to the method instead of being the , operator.

12
  • 1
    Many of us still have to support Internet Explorer.
    – Adrian Larson
    Commented Jun 26, 2020 at 19:12
  • @sfdcfox I'm not sure that this works. It is entering the connected call back, but the functions are not firing. Any ideas?
    – thinker
    Commented Jun 26, 2020 at 20:28
  • @AdrianLarson I thought LWC was supposed to cross-compile (transpile) for IE 11? Much of LWC isn't technically standard tech yet.
    – sfdcfox
    Commented Jun 26, 2020 at 23:00
  • 1
    @sfdcfox This is very helpful, I have a question, when we should use async and when promise? Commented Jun 27, 2020 at 3:58
  • 3
    @rahulgawale They are perfectly interchangeable. You can use whichever you prefer. I like the await/async model, as it is much easier to read in my opinion (which was one of the motivations of this feature).
    – sfdcfox
    Commented Jun 27, 2020 at 4:38

You must log in to answer this question.

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