0

I am calling a javascript function getSObjectfromRecordId and passing in an ID such as "0035f00000DrrSdAAJ".

When the function getSObjectfromRecordId calls the apex method getSObjectFromID, I see that the function does not wait for the promise result and as such, the return value is always 'https://'+location.host;

How can I get the function to wait for the APEX method to complete, so that it can assign the result to the URLField variable?

Below is the code:

Here is how it works...

connectedCallBack() fires upon initialization and then fetchData() triggers. Fetch Data returns a list of SOQL Queried Records.

One of the field values is a look-up to a record ID. My goal is to figure out the SObject of that Record ID.

import getSObjectFromID from '@salesforce/apex/sObjectDatatableController.getSObjectFromId'

getSObjectfromRecordId(recordId)
{
    var URLField = 'https://'+location.host;
    
    getSObjectFromID({strRecordId: recordId})
    .then(result => {
        URLField += '/lightning/r/' + result + '/' + recordId + '/view';
    })
    .catch(error => {
        console.log('Error Occurred in getSObjectfromRecordId:- ' + JSON.stringify(error));
        return error;
    });

    return URLField;
}


connectedCallback() {
            this.fetchData();   
        }

 fetchData(){
        getFieldsAndRecords({ mapVals: this.vals })
        .then(data => {
                    let new_URLs = []
                try{ 
                    for (const key in mapOfLookUpKeys) 
                    {
                    // new_item[new_item]
                    console.log("Value ::"+mapOfLookUpKeys[key])
                    console.log("key ::"+JSON.stringify(key))
                    // console.log('Item '+item)
                    console.log('Item Key '+item[key])
                    let resp = testgetSObjectfromRecordId(item[key]).then(function(result) {
                            console.log(result);
                            return result;
                    }); 
                     new_item = {...new_item, resp};

                    }
                }
                 });
})
4
  • 3
    You should just need basic async/await syntax.
    – Adrian Larson
    Jan 3, 2022 at 1:58
  • @AdrianLarson I keep seeing the following in the console - Promise {<pending>}. How do I unpack this? Jan 3, 2022 at 2:01
  • @AdrianLarson The issue at hand is that res returns as an empty string. Then after the function completes the promise, then it returns the expected return value. Jan 3, 2022 at 2:23
  • 2
    Please stop adding irrelevant tags to your questions. Tags are meant to help describe what topics your question is about, and help people identify questions they may be able to answer. In this particular case, the trigger tag was inappropriate because your question doesn't contain anything related to an SObject Trigger (which is what that tag is meant for).
    – Derek F
    Jan 3, 2022 at 2:59

2 Answers 2

2

This code example is not complete, but the fundamental issue appears to be mixing synchronous and asynchronous code. The function getSObjectfromRecordId() enqueues an asynchronous operation, but doesn't await on it:

getSObjectFromID({strRecordId: recordId})
.then(result => {
    URLField += '/lightning/r/' + result + '/' + recordId + '/view';
})

return URLField;

The call to getSObjectFromID() completes asynchronously, as does the then() closure, but return URLField takes place synchronously. This results in confusing behavior as the promises are ultimately resolved, but note that URLField itself is not a promise.

Switching, as Adrian noted in a comment, to use modern async/await syntax will make the flow of control easier to follow. What you need is something like this (simplified a bit, and you'll have to adapt where the example was unclear or incomplete):

async getSObjectfromRecordId(recordId) {    
    let result = await getSObjectFromID({strRecordId: recordId});

    return `https://${location.host}/lightning/r/${result}/${recordId}/view`;
}


async connectedCallback() {
    await this.fetchData();   
}

async fetchData(){
    let data = await getFieldsAndRecords({ mapVals: this.vals });
    let resp = await getSObjectfromRecordId(item[key]);
}

I've added some modern JS practices here, including async/await, template literal strings, and let rather than var. Adopting these tools can make your code significantly cleaner and more understandable.

3
  • This is very helpful - I continue to get the following error "Unexpected reserved word 'await'" Jan 3, 2022 at 2:49
  • 2
    That likely indicates a syntax error in the preceding lines.
    – David Reed
    Jan 3, 2022 at 2:49
  • @MatthewMetros you cannot use await unless your function is async. That's the reason you're getting this error.
    – sfdcfox
    Jan 3, 2022 at 3:31
2

In the general sense, a Promise does not execute until the system has processed the previous thread of execution. Let's write a really simple example to see what's going on.

let x = 'hello'
setTimeout(() => x = 'hello world')
console.log(x) //output is 'hello'

In order to fix this, we need a Promise. This allows us to return the value asynchronously.

let x = 'hello'
new Promise((resolve) => setTimeout(() => { x = 'hello world'; resolve() }))
  .then(() => {
    console.log(x) // Outputs 'hello world' after the below line executes
  })
console.log(x) // outputs 'hello' before the above line executes

All of this became pretty cumbersome with complicated setups, so we were given async and await, which makes our code look nicer:

let x = 'hello'
await new Promise(async (resolve) => setTimeout(() => { x = 'hello world'; resolve() }))
console.log(x) // Outputs 'hello world'

Similarly, in your code, you would want to use async and await:

async getSObjectfromRecordId(recordId) {
  return `https://${location.host}/lightning/r/${await getSObjectFromID({
    strRecordId: recordId,
  })}/${recordId}/view`;
}
async fetchData() {
  const data = await getFieldsAndRecords({ mapVals: this.vals });
  let output = await Promise.all(
    data.map(async (item) => this.getSObjectFromID(item))
  );
  // Do something with output here
}

This is similar to the David's answer, but I felt some further explanation might be useful in helping you resolve your problem.

1

You must log in to answer this question.

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