angular 6 wait post response - javascript

var data2 = { data1Id: 0 };
postData(){
this._service1.save(data1).subscribe(res => {
this.data2.data1Id = res.Data.Id; //res.Data.Id has valid data
});
this._service2.save(data2).subscribe(res => {
console.log(this.data2.data1Id); //"this.data2.data1Id = 0" can't get value from service1
});
}
how can i get data from the first service or some function take me resolve problem run call service sequence. thank for watching !

Using async/await is perfect for your situation. It will help you to make your code more readable and make abstraction of the async part thanks to the await keyword
aync post(){
const res1 = await this._service1.save(this.data1).toPromise();
const res2 = await this._service2.save(res1).toPromise();
console.log('here is my data 2 ' + res2);
return 'what you want, can be res1 or res2 or a string';
}
How to call it ?
this.myService.post().then( (whatYouWanted) => {
console.log(whatYouWanted); // what you want, can be res1 or res2 or a string
});

this._service1.save(data1).flatMap(res => {
this.data2.data1Id = res.Data.Id; //res.Data.Id has valid data
return this._service2.save(data2);
}).subscribe(res => {
console.log(this.data2.data1Id); //"this.data2.data1Id = 0" can't get value from service1
});
You can use flatMap and return the second observable to chain them.
Documentation: http://reactivex.io/documentation/operators/flatmap.html

Related

How to add MySQL query results from a loop in Nodejs?

Essentially, I have an object with string keys and values (ex. {"michigan":"minnesota"}). I'm trying to loop through all of these key value pairs and make a query from my database, and add the result to a list, which will then be what is returned to the front end.
var return_list = []
Object.keys(obj).forEach(function(key){
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
db.query(sql_select,[state1,state2], (err,result) => {
return_list.push(result);
});
})
This is what I have in simplest terms, and would like to send return_list back to the front end. The problem I'm running into is I can console.log the result within db.query call, but I can't push the result to the list or call it anywhere outside of the query. I'm fairly new to both front end and back end development, so any possible ideas would definitely be helpful!
The problem is that the forEach returns void.
So you can't wait for the asynchronous code to run before you return it.
When we're dealing with an array of promises such as db queries ( like in your case ) or API calls, we should wait for every one of them to be executed.
That's when we use the Promise.all
Try doing it like this:
const queryResults = await Promise.all(
Object.keys(obj).map(async (key) => {
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
return new Promise((resolve, reject) =>
db.query(sql_select,[state1,state2], (err, result) => {
if (err)
return reject(err)
else
return resolve(result)
})
)
})
)
console.log('queryResults', queryResults)
// now you give this queryResults back to your FE
Small tips for your fresh start:
never use var, try always use const or if needed, let.
try always use arrow functions ( () => {...} ) instead of regular functions ( function () {...} ), It's hard to predict which scope this last one is using
The issue is because the database transaction is not instant, so you need to use either promises or async-await.
Using async await would be something like this (untested),
async function get_return_list () {
var return_list = []
Object.keys(obj).forEach(function(key){
const state1 = key;
const state2 = obj[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
await db.query(sql_select,[state1,state2], (err,result) => {
return_list.push(result);
});
})
return return_list
}
see for more detail: https://eloquentjavascript.net/11_async.html
First, make sure you are working with mysql2 from npm. Which provides async method of mysql.
Second, Note that when you query SELECT, you don't get the "real" result in first. Suppose you get result, then, the "real" results are held in result[0].
(async () => {
const promiseArr = [];
for (const key of Object.keys(yourOBJ)) {
const state1 = key;
const state2 = yourOBJ[key];
const sql_select = 'SELECT column1,column2 from database WHERE state = ? OR state=?';
promiseArr.push(db.query(sql_select, [state1, state2]));
}
let results;
try {
results = await Promise.all(promiseArr);
} catch (e) {
throw '...';
}
const return_list = results.reduce((finalArray, item) => {
finalArray = [
...finalArray,
...item[0],
]
}, []);
})();

Why does this scrape return undefined?

When I run this code I get undefined but it is clear that the ski and product_id are in the value form.
I want:
value="BTdtb4CBz3uSJ2qv"
value="adi-ss20-042"
but I get "undefined"
class TresBien {
async scrapeRaffleInfo() {
// scrape the form_key and sku values
const response = await axios(
"https://tres-bien.com/adidas-yeezy-boost-380-mist-fx9764-ss20"
);
console.log("response: ", response);
const html = await response.data;
const $ = cheerio.load(html);
const res = $('input[name="sku"]').val();
const ans = $('input[name="form_key"]').val();
console.log(res && ans);
}
}
const main = async () => {
const tb = new TresBien(
"https://tres-bien.com/adidas-yeezy-700-v3-alvah-h67799-ss20"
);
let checkoutSucc = await tb.scrapeRaffleInfo();
if (checkoutSucc) {
Logger.logEventSuccess("Raffle successfully entered");
}
};
main();
There are a few things wrong in your code:
as #Pointy mentioned, scrapeRaffleInfo() is returning undefined and you're trying to use it in checkoutSucc
Tresbien class doesn't offer any constructor, yet you're passing your url as a parameter to the constructor of that class.
You're not using any of axios library methods (like: get(), post(), put(), delete()). typically you need axios.get() but there in your code, you're just using axios()

Having some confusion around how to properly handle javascript promises with axios

So I have two simple functions, the first function makes an api call and retrieves 100 category ids and stores them in an array. I use lodash to randomly pick 6 of these category ids. The second function is suppose to make use of these 6 unique category ids and use them in the query string for the next 6 api calls made in the second function.
async function getCategoryIds() {
const res = await axios.get('http://jservice.io//api/categories?count=100');
for (let cat of res.data) {
categories.push(cat.id)
}
var sampleCategories = _.sampleSize(categories, 6);
console.log(sampleCategories);
return sampleCategories;
}
getCategoryIds()
.then(getCategory)
async function getCategory(sampleCategories) {
const res1 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[0]}`);
const res2 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[1]}`);
const res3 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[2]}`);
const res4 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[3]}`);
const res5 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[4]}`);
const res6 = await axios.get(`http://jservice.io/api/category?id=${sampleCategories[5]}`);
}
getCategory();
However, no matter how I rework it I still cannot get this error to go away:
Uncaught (in promise) TypeError: Cannot read property '0' of undefined
Could somebody steer my in the right direction?
Thank you.
if your backend is exactly sending response an exact array then you should
dont forget to give args when u r calling getCategory function
then edit your getCategory function
async function getCategory(sampleCategories) {
let arr = []
const res1 = await axios.get('any url you want')
//repeat 6 times
arr = [res1, res2, ...otherElems]
return arr
}
with 'then' syntax
getCategoryIds()
.then(response => getCategory(response))
with async await syntax
const firstResponseArr = await getCategoryIds();
const secondResponseArr = await getCategory(firstResponseArr);
Your Mistake
Calling getCategory(); with passing any argument. Clearly async function getCategory(sampleCategories) needs an argument - sampleCategories which you failed to pass.
Error intepretation
Uncaught (in promise) TypeError: Cannot read property '0' of undefined # sampleCategories
Call getCategory() with an argument
This has nothing to do with axios but with your careless mistake. (Don't worry, it happens to even the best of us)
Alright so what I was struggling with was trying to figure out how to properly utilize async/await -- this seemed to work for me:
let categories = []
var sampleCategories = []
async function getCategoryIds() {
const res = await axios.get('http://jservice.io//api/categories?count=100');
for (let cat of res.data) {
categories.push(cat.id)
}
var sampleCategories = _.sampleSize(categories, 6);
return sampleCategories;
}
getCategoryIds()
async function getCategory() {
var y = await getCategoryIds();
const res1 = await axios.get(`http://jservice.io/api/category?id=${y[0]}`);
const res2 = await axios.get(`http://jservice.io/api/category?id=${y[1]}`);
const res3 = await axios.get(`http://jservice.io/api/category?id=${y[2]}`);
const res4 = await axios.get(`http://jservice.io/api/category?id=${y[3]}`);
const res5 = await axios.get(`http://jservice.io/api/category?id=${y[4]}`);
const res6 = await axios.get(`http://jservice.io/api/category?id=${y[5]}`);
let arr = [res1, res2, res3, res4, res5, res6]
return arr
}
getCategory();

Pushing elements into the array works only inside the loop

I got some data which I'm calling from API and I am using axios for that. When data is retrieved, I dump it inside of a function called "RefractorData()" just to organize it a bit, then I push it onto existing array. The problems is, my array gets populated inside forEach and I can console.log my data there, but once I exit the loop, my array is empty.
let matches: any = new Array();
const player = new Player();
data.forEach(
async (match: any) => {
try {
const result = await API.httpRequest(
`https://APILink.com/matches/${match.id}`,
false
);
if (!result) console.log("No match info");
const refractored = player.RefractorMatch(result.data);
matches.push({ match: refractored });
console.log(matches);
} catch (err) {
throw err;
}
}
);
console.log(matches);
Now the first console.log inside forEach is displaying data properly, second one after forEach shows empty array.
Managed to do it with Promise.all() and Array.prototype.map()
.
const player = new Player();
const matches = result.data;
const promises = matches.map(async (match: any) => {
const response: any = await API.httpRequest(
`https://API/matches/${match.id}`,
false
);
let data = response.data;
return {
data: player.RefractorMatch(data)
};
});
const response: any = await Promise.all(promises);
You must understand that async functions almost always run later, because they deppend on some external input like a http response, so, the second console.log is running before the first.
There a few ways to solve this. The ugliest but easiest to figure out is to create a external promise that you will resolve once all http requests are done.
let matches = [];
let promise = new Promise((resolve) => {
let complete = 0;
data.forEach((match: any) => {
API.httpRequest(...).then((result) => {
// Your logic here
matches.push(yourLogicResult);
complete++;
if (complete === data.length) {
resolve();
}
}
}
};
console.log(matches); // still logs empty array
promise.then(() => console.log(matches)); // now logs the right array
You can solve this using other methods, for example Promise.all().
One very helpful way to solve it is using RxJs Observables. See https://www.learnrxjs.io/
Hope I helped you!

Unable to receive proper data from the promise function

I am trying to scrap wikipedia page to fetch list of airlines by first scrapping first page and then going to each individual page of airline to get the website url. I have divided the code in two functions. One to scrap main page and get a new url, and second function to scrap another page from the created url to get the website name from that page. I have used request-promise module for getting the html and then cheerio to parse the data.
export async function getAirlinesWebsites(req,res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log('Response got');
$('tr').each((i,e)=>{
let children = '';
console.log('inside function ', i);
if($(e).children('td').children('a').attr('class') !== 'new') {
children = $(e).children('td').children('a').attr('href');
let wiki_url = 'https://en.wikipedia.org' + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
})
And then the getAirlineUrl() function will parse another page based on the provided url.
async function getAirlineUrl(url){
const wiki_child_options = {
url : url,
headers : headers
}
let child_response = await request(wiki_child_options);
let $ = cheerio.load(child_response);
let answer = $('.infobox.vcard').children('tbody').children('tr').children('td').children('span.url').text();
return answer;
})
However when I console log the answer variable in the parent function, I get a [object Promise] value instead of a String. How do I resolve this issue?
Async function return promise.In case of that,you need to use then to get resolved response or use await.
This should work if other part of your code is ok.
export async function getAirlinesWebsites(req, res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log("Response got");
$("tr").each(async (i, e) => {
let children = "";
console.log("inside function ", i);
if ($(e).children("td").children("a").attr("class") !== "new") {
children = $(e).children("td").children("a").attr("href");
let wiki_url = "https://en.wikipedia.org" + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = await getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
});
}
Since your getAirlineUrl function returns a promise, you need to await that promise. You can't have await nested inside of the .each callback because the callback is not an async function, and if it was it wouldn't work still. The best fix is the avoid using .each and just use a loop.
export async function getAirlinesWebsites(req,res) {
let response = await request(options_mainpage);
console.log(`Data`);
let $ = cheerio.load(response);
console.log('Response got');
for (const [i, e] of Array.from($('tr')).entries()) {
let children = '';
console.log('inside function ', i);
if($(e).children('td').children('a').attr('class') !== 'new') {
children = $(e).children('td').children('a').attr('href');
let wiki_url = 'https://en.wikipedia.org' + children;
console.log(`wiki_url = ${wiki_url}`);
let airline_url = await getAirlineUrl(wiki_url);
console.log(`airline_url = ${airline_url}`);
}
}
}

Categories

Resources