Why return variable is empty [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 months ago.
Console log inside if block prints but return value is empty, why ? i have create let emailHtml varaible to whom i am assigning value in the block
cy.request('GET', `https://api.testmail.app/api/json?apikey=${APIKEY}&namespace=${NAMESPACE}&tag=dev`).then(
(response) => {
if (response.body.emails.length != 0) {
response.body.emails.forEach((email: any) => {
if (email.subject === subject) {
emailHtml = email.html;
console.log(emailHtml); // prints
}
});
}
if (response.body.emails.length === 0) {
cy.wait(3000);
TestMailService.getLatestEmail(subject, ++attempts);
}
},
);
console.log(emailHtml); // empty
return emailHtml;
}

My solution that might help others
export class TestMailService {
static async getLatestEmailBySubject(subject: string) {
let emailAsHtml: string = '';
const NAMESPACE: string = '';
const APIKEY: string = '';
let emailSentTimeStamp: string = Math.round(Date.now() - 120000).toString();
for (let i = 0; i <= 40; i++) {
const response: Inbox = await new Cypress.Promise((resolve, reject) => {
cy.request<Inbox>(
'GET',
`https://api.testmail.app/api/json?apikey=${APIKEY}&namespace=${NAMESPACE}&tag=testnow2&timestamp_from=${emailSentTimeStamp}`,
).then((response: Inbox) => {
resolve(response);
reject('bad request');
});
});
if (response.body.emails.length === 0) {
cy.wait(3000);
} else if (
response.body.emails.length > 0 &&
response.body.emails[0].subject === subject &&
response.body.emails[0].timestamp > emailSentTimeStamp
) {
emailAsHtml = response.body.emails[0].html;
break;
}
}
return emailAsHtml;
}
}

Related

Get response with promise [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I'm trying to get the value returned from an API query, but in all the ways I've done it, it either returns Undefined or [object Promise]. I've tried several solutions and I still haven't got something that works. Below is the last code I made to see if it worked but again without success.
function generateLink(link) {
const url = 'https://api.rebrandly.com/v1/links';
const options = {
method: 'POST',
uri: url,
headers: {'Content-Type': 'application/json', apikey: 'xxxxxxxxxxxxxxxxxxxxx'},
body: JSON.stringify({destination: link})
};
return requestPromise(options).then(response => {
if ( response.statusCode === 200 ) {
return response.body
}
return Promise.reject(response.statusCode)
})
}
...
bot.onText(/\/offers (.+)/, function onEchoText(msg, match) {
console.log(match[1]);
if (isNaN(match[1])) {
bot.sendMessage(msg.from.id, 'Enter a valid number! \nExample: /offers 5');
} else {
client.execute('aliexpress.affiliate.product.query', {
'app_signature': 'defualt',
'category_ids': '701,702,200001081,200001388,200001385,200386159,100000616,100001205,5090301',
'target_currency': 'USD',
'target_language': 'EN',
'tracking_id': 'defualt',
'ship_to_country': 'US',
}, function (error, response) {
var code = response.resp_result.resp_code;
var mesage = response.resp_result.resp_msg;
if (code === 200) {
var i;
var temCupom = [];
var link = [];
var itemList = response.resp_result.result.products.product;
for (i = 0; i < match[1]; i++) {
temCupom[i] = itemList[i].promo_code_info ? "🏷 <b>There's a coupon!</b>: " + itemList[i].promo_code_info.promo_code : "";
(async () => {
link[i] = generateLink(itemList[i].promotion_link).then(body => { return body.shortUrl })
})();
bot.sendPhoto(msg.chat.id, itemList[i].product_main_image_url, {
caption: "❤ <b>Promotion</b> ❤\n" +
"💵 <b>Price</b>: " + Number(itemList[i].target_sale_price).toLocaleString('en-us', { style: 'currency', currency: 'USD' }) + "\n" +
"🛒 <b>Link</b>: " + link[i] + "\n" +
temCupom[i],
});
}
}
else {
bot.sendMessage(msg.from.id, 'Deu errado! ' + mesage);
}
})
}
});
link[i] need to return the links generated with the API
Option 1 (with async/await):
if (code === 200) {
var i;
var link = [];
var itemList = response.resp_result.result.products.product;
for (i = 0; i < match[1]; i++) {
link[i] = await generateLink(itemList[i].promotion_link).then(body => { return JSON.parse(body).shortUrl })
}
}
Option 2 (with Promise):
if (code === 200) {
var link = [];
var itemList = response.resp_result.result.products.product;
for (let i = 0; i < match[1]; i++) {
generateLink(itemList[i].promotion_link).then(body => { link[i] = JSON.parse(body).shortUrl })
}
}
Option 3 (Promise.all takes all URLs in parallel mode):
if (code === 200) {
const itemList = response.resp_result.result.products.product;
const requests = itemList.slice(0, match[1])
.map(item => generateLink(item.promotion_link).then(body => JSON.parse(body).shortUrl));
const links = await Promise.all(requests);
}
===============================
Updated:
After all, we realized that the body was a string and it was necessary to do JSON.parse
You need to assign the result in the then block.
You can make some simple changes, like putting link[i] = result into the then block, but there are problems like the fact that value of i will be the same. Also, if you want the values populated after the for loop, you'll notice that they have not been filled. You need to wait till they are all resolved (faking with timeout below).
function generateLink(link) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Math.random())
}, 1)
})
}
if (200 === 200) {
var i;
var link = [];
var MAX = 10;
for (i = 0; i < MAX; i++) {
generateLink('🤷‍♂️').then(result => {
link[i] = result; // no bueno - since i will be 10 when this is resolved
})
}
console.log(link) // still not resolved
setTimeout(() => {
console.log(link) // 🤦‍♂️ [undefined * 9, value]
}, 10)
}
// async version (note use of `async`)
(async function(){
var MAX = 10;
var link = []
for (i = 0; i < MAX; i++) {
link[i] = await generateLink('🤷‍♂️')
}
console.log(link)// 👍
})()
So you can add more complexity to make it work, but async/await is likely the way to go if you can support it.
for (i = 0; i < match[1]; i++) {
link[i] = await generateLink(itemList[i].promotion_link).then((body) => {
return body.shortUrl;
});
}
Also if you use await the promises will execute in series, which you might not want. Resolving in parallel is faster, but you could also run into issue if you're going to have too many network requests they'll need to be throttled, so async await may work better)

Control not being returned from promise

I am trying to register a user using AWS Cognito. In the below class, the control from theregisterInCognito is not being returned. I have tried adding return after the failure and success conditions too (aren't reject and resolve of the promise the same?). But nothing worked. When I tried debugging, I figured out that the section where I have commented <---- The control is unreachable here. is not being executed. The control itself is in the return function.
export class CompanyCAO {
// change return type from any to meaningful type
private poolData;
private pool_region;
private userPool;
private cognitoUser;
constructor() {
this.poolData = {
UserPoolId: process.env.COGNITO_USER_POOL_ID,
ClientId: process.env.COGNITO_CLIENT_ID
}
this.pool_region = process.env.COGNITO_POOL_REGION;
this.userPool = new AmazonCognitoIdentity.CognitoUserPool(this.poolData);
}
public create(regInfo: Company): Promise < any > {
return new Promise < boolean > (async(resolve, reject) => {
this.registerInCognito(regInfo);
});
}
public registerInCognito(regInfo: Company): Promise < boolean > {
return new Promise < boolean > (async(resolve, reject) => {
let attributes = process.env.COGNITO_AUTH_ATTRIBUTES!.split(",");
let attributeValues = Array < string > ();
let attributesList = Array < any > ();
for (var attribute in attributes) {
for (var attributeName in regInfo) {
if (((typeof regInfo[attributeName]) != 'object') && (attributes[attribute] == attributeName)) {
attributeValues.push(regInfo[attributeName]);
} else if ((typeof regInfo[attributeName]) === 'object') {
for (var subAttributeName in regInfo[attributeName]) {
if (subAttributeName == attributes[attribute]) {
attributeValues.push(regInfo[attributeName][subAttributeName]);
}
}
}
}
}
for (var index in attributes) {
attributesList.push(new AmazonCognitoIdentity.CognitoUserAttribute({
Name: attributes[index],
Value: attributeValues[index]
}));
}
const randomPassword = this.createRandomPassword();
console.log(`Password is ${randomPassword}`);
await this.userPool.signUp(regInfo.Admin.EmailAddress, randomPassword, attributesList, null, (err, result) => {
if (err) {
console.error(err);
reject(err);
} else {
this.cognitoUser = result.user;
}
}).promise().then((value: any) => {
resolve(true);
}).catch(error => {
reject(error);
})
});
// <---- The control is unreachable here.
}
public createRandomPassword() {
let password = '';
const alphaCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numberCharacters = '1234567890';
const specialCharacters = '!##$%^&**()?/><}{';
const iterations = 5;
for (let i = 0; i < iterations; i++) {
password += alphaCharacters.charAt(Math.floor(Math.random() * alphaCharacters.length));
password += numberCharacters.charAt(Math.floor(Math.random() * numberCharacters.length));
password += specialCharacters.charAt(Math.floor(Math.random() * specialCharacters.length));
}
return password;
}
}

Javascript loop not returning true, when String === String

When looping through an array to find if the array contains a word that I am looking for, the loop always returns 'false' when if I console.log out the what is being compared I can clearly see that the word I am looking for (collectionNameLookingFor) is in the array (collectionNameArray) so it should return true.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayofCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
function saveContentToDb(req, res) {
const db = getDb();
const pageDetails = req.body;
let saveType;
db.db(pageDetails.databaseName).listCollections().toArray((error, collections) => {
if (error) {
throw error;
} else {
collections.map(collection => (collection.name)).forEach(collectionNameArray => {
const collectionNameLookingFor = req.body.page;
const check = checkCollectionNames(collectionNameArray, collectionNameLookingFor);
console.log('===========Looking to see if it is true or false==========');
console.log(check);
console.log(`Name of collection in Database: ${collectionNameArray} ::: ${collectionNameLookingFor}`);
console.log('==========================================================');
if (check === true) {
saveType = 'updated';
console.log(`saveType = ${saveType}`);
} else {
saveType = 'created';
console.log(`saveType = ${saveType}`);
}
});
}
});
}
You might need to check against collectionName, because that is the parameter you hand over, beside arrayOfCollections, instead of the array itself.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayOfCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
Short Version:
function checkCollectionNames(arrayOfCollections, collectionName) {
return arrayOfCollections.includes(collectionName);
}

Using Class to store all data in a object [duplicate]

This question already has answers here:
Async/Await Class Constructor
(20 answers)
Is it bad practice to have a constructor function return a Promise?
(5 answers)
Closed 4 years ago.
I have used a class for fetching all data to store in a one object. But the object is undefined after running successfully its seems that data is stored in object(Alloptions).
I have tried but can not find sutiable way of doing
router.get('/:category', (req, res) => {
let AllOptions;
let cat4;
AllOptions = new GetAllOptions(); //show undefined
let category = req.params.category.replace(/-/g, ' ')
console.log(AllOptions)
for (i = 0; i < AllOptions.categories.length; i++) {
console.log(AllOptions.categories[i].categoryName.replace(/-/g, ' ').toLowerCase())
console.log(category)
if (AllOptions.categories[i].categoryName.replace(/-/g, ' ').toLowerCase() == category) {
cat4 = AllOptions.categories[i].categoryId - 1
}
}
})
Class object
class GetAllOptions {
constructor() {
this.categories = {};
this.languages = {};
this.getJobCategories();
}
async getJobCategories() {
await Category.getAllCategories((err, response) => {
if (err) {
//?? how error flash dont know
return res.json({
error: ERROR_MSG,
});
}
if (response.length > 0) {
for (let i = 0; i < response.length; i++) {
this.categories[response[i].categoryId] =
response[i];
}
for (let i = 0; i < response.length; i++) {
this.categoriesNames[response[i].categoryName] =
response[i];
}
}
})
this.getJobLanguages();
}
async getJobLanguages() {
await Category.getAllLanguages((err, response) => {
if (err) {
//?? how error flash dont know
return res.json({
error: ERROR_MSG,
});
}
if (response) {
for (let i = 0; i < response.length; i++) {
this.languages[response[i].languageId] =
response[i];
console.log(this.languages[response[i].languageId])
}
for (let i = 0; i < response.length; i++) {
this.languagesNames[response[i].languageName] =
response[i];
}
}
})
}
}
I want to wait until class run completed and fetch all data but here showing undefined
you can construct your GetAllOptions object asynchronously :
constructor (async_param) {
if (typeof async_param === 'undefined') {
throw new Error('Cannot be called directly');
}
}
static async build () {
var async_result = await getJobCategories()();
return new myClass(async_result);
}

ES6 Class method is not a function only happening on one method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Calling a class prototype method by a setInterval event
(3 answers)
Closed 5 years ago.
I'm trying to take a more OOP approach to the way I write Javascript. As a relative beginner, I'm a bit confused by the error I'm getting Uncaught TypeError: this.getCoinSelOption is not a function at getBTC. I have the this keyword calling other methods in my class, but it does not want to call a different method on an interval. What should I do here?
How I'm calling:
coins.getBTC(abbr)
setInterval(coins.getBTC, 10000)
I can call the method initially, but when I need to redetermine the abbreviation of the BitCoin, I go to the global const abbr and update the value based on what's selected through the select tag
class Coins {
constructor () {
this.coinOptions = document.getElementById('coinOptions');
}
getCoinObjects (url) {
let promise = new Promise((resolve, reject) => {
fetch(url)
.then(response => {
resolve(response.json().then(data => {
let coins = []
for (var key in data.Data) {
coins.push(data.Data[key])
}
//this is working here!
this.getCoinOptions(coins)
return coins
}))
})
.catch(response => {
reject('“Api call failed!”')
})
})
.then(response => {
return coins
})
.catch(response => {
console.log('error: ' + response)
})
}
getCoinOptions(keys) {
for (var i = 0; i < keys.length; i++) {
var opt = document.createElement('option');
opt.value = keys[i].Symbol
opt.innerHTML = keys[i].CoinName
this.coinOptions.appendChild(opt)
}
}
getBTC(abbr) {
if (abbr === undefined) {
//this not working here
abbr = this.getCoinSelOption(this.coinOptions)
console.log('this is the abbr' + abbr)
}
axios.get('https://min-api.cryptocompare.com/data/pricemulti?fsyms='+abbr+'&tsyms=USD')
.then(res => {
console.log(abbr)
const cryptos = res.data[abbr].USD
price.innerHTML = '$'+cryptos.toLocaleString('en')
if (targetPrice.innerHTML != '' && targetPriceVal < res.data[abbr].USD) {
const myNotification = new window.Notification(notification.title, notification)
}
return abbr
})
setTimeout(this.getBTC, 10000)
}
getCoinSelOption(sel) {
console.log('called')
loadBounce.classList.add('loading')
this.getBTC(sel.options[sel.selectedIndex].value)
setTimeout(function() {
loadBounce.classList.remove('loading')
}, 900)
return sel.options[sel.selectedIndex].value
}
}

Categories