How to wait a loop in angular - javascript

I am new in angular and trying to do some loop operation in firebase. I want to fetch all the information by email id.
user_info = [];
for (let index = 0; index < this.email.length; index++) {
this.get_student_service
.get_student_by_email_id(this.email[index])
.subscribe((res) => {
this.user_info.push(res);
console.log(this.user_info);
});
}
console.log(this.user_info);
output:-
But I want print user_info after loop complete there execution

Fork Join will resolve your problem I guess, please try it out.
forkJoin(
this.email.map(email => this.get_student_service.get_student_by_email_id(email)
)
.subscribe(res => {
console.log(this.user_info); // will print result as an array
})

Instead of a for loop you could use the map method of the email array and then use an Observable.forkJoin to handle all the results at the same time.
Something like this:
import { forkJoin } from 'rxjs';
const getStudentsRequests = this.email.map(email =>
this.get_student_service.get_student_by_email_id(email);
);
forkJoin(getStudentsRequests).subscribe(resultArray => (this.user_info = resultArray));

Related

How to make multiple requests and save the data objects into a new array

I have two methods, which make a GET request. The first method saves user objects into the Benutzer array and in the benutzerIDs array only the user ids are saved. In the second method I'd like to loop through the benutzerIDs array and use these IDs for another GET Request and save the Objects into the array test. I have a problem with executing this request because of the multiple IDs. Currently I can't save the data into test. How can I loop throught the benutzerIDs and make a request based on this IDs?
getBenutzerDesVorgesetzten(id) {
axios
.get(server.baseURL + "/benutzer/vorgesetzter/" + id)
.then(response => {
this.benutzerIDs = [];
this.Benutzer = response.data;
this.Benutzer.forEach((item) => {
this.benutzerIDs.push(item.BenutzerID);
});
});
this.getAnträgeByBenutzerID();
},
getAnträgeByBenutzerID(){
this.test = [];
this.benutzerIDs.forEach((id) =>
this.test = axios.all([axios.get(server.baseURL + "/urlaubsantrag/benutzer/" + id)]))
}
Try this:
getAnträgeByBenutzerID(){
this.test = [];
const promises = [];
this.benutzerIDs.forEach(id => {
promises.push(axios.get(server.baseURL + "/urlaubsantrag/benutzer/" + id))
})
axios
.all(promises)
.then(res =>
//res is an array of raw data
this.test = res.map(item => item.data);
)
}
You'll need to use Promise.all and Array.prototype.map:
getAnträgeByBenutzerID(){
return Promise.all(this.benutzerIDs.map((id) =>
axios.get(server.baseURL + "/urlaubsantrag/benutzer/" + id)])));
}
The map callback creates an array of promises which are then collectively returned once they are all resolved.

asynchronous loop for in Javascript

I'm trying to iterate and print out in order an array in Javascript that contains the title of 2 events that I obtained from doing web scraping to a website but it prints out in disorder. I know Javascript is asynchronous but I'm new in this world of asynchronism. How can I implement the loop for to print the array in order and give customized info?
agent.add('...') is like console.log('...'). I'm doing a chatbot with DialogFlow and NodeJs 8 but that's not important at this moment. I used console.log() in the return just for debug.
I tried the next:
async function printEvent(event){
agent.add(event)
}
async function runLoop(eventsTitles){
for (let i = 0; i<eventsTitles.length; i++){
aux = await printEvent(eventsTitles[i])
}
}
But i got this error error Unexpected await inside a loop no-await-in-loop
async function showEvents(agent) {
const cheerio = require('cheerio');
const rp = require('request-promise');
const options = {
uri: 'https://www.utb.edu.co/eventos',
transform: function (body) {
return cheerio.load(body);
}
}
return rp(options)
.then($ => {
//** HERE START THE PROBLEM**
var eventsTitles = [] // array of event's titles
agent.add(`This mont we have these events available: \n`)
$('.product-title').each(function (i, elem) {
var event = $(this).text()
eventsTitles.push(event)
})
agent.add(`${eventsTitles}`) // The array prints out in order but if i iterate it, it prints out in disorder.
// *** IMPLEMENT LOOP FOR ***
agent.add(`To obtain more info click on this link https://www.utb.edu.co/eventos`)
return console.log(`Show available events`);
}).catch(err => {
agent.add(`${err}`)
return console.log(err)
})
}
I would like to always print out Event's title #1 and after Event's title #2. Something like this:
events titles.forEach((index,event) => {
agent.add(`${index}. ${event}`) // remember this is like console.log(`${index}. ${event}`)
})
Thanks for any help and explanation!
There no async case here but if you still face difficultly than use this loop
for (let index = 0; index < eventsTitles.length; index++) {
const element = eventsTitles[index];
agent.add(${index}. ${element})
}

Angular get response after subscribe loops end

thanks in advance for your time.
I am looping 2 services endpoints to get data, the problem that I am facing is that I would like to wait for the first subscribe to finish in order to loop the other one, but the result outside of the first subscribe is empty and if I place the second loop within the previous subscribe, I am facing duplications and/or undefined variables.
I have tried two ways
The first solution i have tried is looping the service endpoint and then looping the other service endpoint inside the first subscribe. The problem with this solution is that i am facing duplicates and/or undefinend variables.
The second solution i tried is using forkJoin, but i have two problems with this one.
The first problem i have using forkJoin is that i am getting a Pageable from my backend (using java - spring boot) to manage the pagination, so i cannot do a proper pagination because the forkJoin retrieve the Pagination in an Array, so the details are no longer useful, since it is splitted in the array.
The second problem i have using forkJoin is that everytime i click again to fetch the data it is adding the result to the old one, making endless duplicates (even when i set my arry to empty everytime i press the button)
I will share with you guys both examples i have tried and the service endpoints i am using
Service 1:
getAllQuestionsEvaluation(page: number, level: number, profu: number, idComponent: number): Observable<any> {
return this.http.get(this.urlEndpoint + 'page/' + page + '/' + level + '/' + profu + '/' + idComponent, {headers: this.headerService.addAuthHeader()}).pipe(
catchError((e) => {
this.headerService.serverError(e);
if (this.headerService.isNoAuth(e)) {
this.appDialogService.confirm();
}
return throwError(e);
})
);
}
I first loop that endpoint and then i need to loop the result for the next service to get the other data:
Service 2:
getAllByIdQuestion(idQuestion: number): Observable<any> {
return this.http.get(this.urlEndpoint + 'findbyidq/' + idQuestion, {headers: this.headerService.addAuthHeader()}).pipe(
catchError((e) => {
this.headerService.serverError(e);
if (this.headerService.isNoAuth(e)) {
this.appDialogService.confirm();
}
return throwError(e);
})
);
}
The first code i have been trying is the following, however i and facing duplicates and problems with the result:
jsonComponentsResult is the array result of components, however that service is not looping, so i am facing no problems with it and that is why i am not sharing that code.
this.questions = [];
this.questionsToCompare = [];
for (let com of jsonComponentsResult) {
this.questionService.getAllQuestionsEvaluation(0, this.evaluation.level, this.evaluation.profu, com.idComponent.idComponent).subscribe(
(jsonQuestions) => {
this.questionsToCompare = this.questionsToCompare.concat(jsonQuestions.content);
for (let i = 0; i < this.questionsToCompare.length; i++) {
this.questionsGradeService.getAllByIdQuestion(this.questionsToCompare[i].idQuestion).subscribe(
(response) => {
this.questionsGrades = this.questionsGrades.concat(response);
for (let p of this.questionsGrades) {
if (this.evaluation.idGrade.idGrade === p.idGrade.idGrade) {
this.questions = this.questions.concat(p.idQuestion);
}
}
this.dataSource = new MatTableDataSource < Questions > (this.questions);
}
);
}
this.pageIndex = jsonQuestions.number;
this.pageSize = jsonQuestions.size;
this.length = jsonQuestions.totalElements;
},
(error) => {
console.log(error);
}
);
}
My second solution is to use ForkJoin, however as i mentioned before, i am not able to manage my pagination and i am getting duplicates everytime i press the button even though i am setting the arrays to empty []:
observables: Observable < Questions > [] = [];
observablePG: Observable < QuestionsGrade > [] = [];
this.questions = [];
this.questionsToCompare = [];
this.questionsGrades = [];
for (let i = 0; i < jsonComponentResult.length; i++) {
this.observables.push(this.questionService.getAllQuestionsEvaluation(0, this.evaluation.level, this.evaluation.profu, jsonComponentResult[i].idComponent.idComponent));
}
Observable.forkJoin(this.observables).subscribe(
(response) => {
for (let x of response) {
this.questionsToCompare = this.questionsToCompare.concat(x);
}
this.observables = [];
this.getQuestions(this.questionsToCompare);
},
(e) => {
console.log(e);
}
);
private getQuestions(questionsArray: any) {
for (let i = 0; i < questionsArray.length; i++) {
this.observablePG.push(this.questionsGradeService.getAllByIdQuestion(questionsArray[i].idQuestion));
this.questions = [];
this.questionsToCompare = [];
}
Observable.forkJoin(this.observablePG).subscribe(
(response) => {
for (let x of response) {
this.questionsGrades = this.questionsGrades.concat(x);
}
this.observablePG = [];
for (let p of this.questionsGrades) {
if (this.evaluation.idGrade.idGrade === p.idGrade.idGrade) {
this.questions = this.questions.concat(p.idQuestion);
}
}
this.dataSource = new MatTableDataSource < Questions > (this.questions);
},
(e) => {
console.log(e);
}
);
}
I would like to wait for the first subscribe to finish in order to loop the other one, but i haven't been able to find a solution, since it looks like looping those services at the same time are causing troubles, and with the forkJoin i am losing my pagination and i am getting all the list again everytime i press the button.
I would like to get the questions list, then, get the questionsGrades to compare if i should add that question to my questions array.
Sorry for the long post and thank you for your time.
Maybe rxjs operator decision tree page could help you with this.
And the second, I remember that I had a similar issue, the only difference was that the value from the first Observable was used as a param in a second one, and for that I used switchMap operator.

Vue.js combine data from RESP API

I need combine multple API calls on a final object, this because API have limits to be consumed, any have an idea how is possible combine multiple calls in same final object, next is an example of my code, I need all data in this.lista but is not working:
created(){
this.$http.get('/api/transactions?senderId=8642612272713533685S&limit=1&offset=000')
.then( function(res){
console.log(res.body.count);
let limit = Math.ceil(res.body.count/1000);
console.log(limit);
let m = {};
let off = 0;
for (var i = 0; i <= limit; i++) {
this.$http.get('/api/transactions?senderId=8642612272713533685S&limit=1000', {params:{offset: off}})
.then( function(data){
this.lista = { ...this.lista, ...data.body.transactions }
} )
off = off + 1000;
}
}
);
}
any help will be appreciated
Using Promise.all is most likely what you are looking for. I will write just enough code for you to understand where to go.
// Populate your array array with URLs you want to get
let urls = ["url1", "url2", "...and so on"];
// Make into web request promises
let httpReqPromises = urls.map( url => this.$http.get(url) )
// Wait for all of them to resolve
Promise.all(httpReqPromises).then(allResponses => {
// Put them all together
this.lista = allResponses.reduce((a, b) => ({...a, ...b}, {})
})
The only work I leave up to you is how you populate the url variable.

React Axios API call with array loop giving wrong order?

I was learning react and doing some axios api call with an array. I did a code on gathering data through coinmarketcap api to learn.
So, my intention was to get the prices from the api with a hardcoded array of cryptocurrency ids and push them into an array of prices. But I ran into a problem with the prices array, as the prices were all jumbled up. I was supposed to get an array in this order
[bitcoinprice, ethereumprice, stellarprice, rippleprice]
but when I ran it in the browser, the prices came randomly and not in this order, sometimes I got my order, sometimes it didn't. I used a button which onClick called the getPrice method. Does anyone know what went wrong with my code? Thanks!
constructor(){
super();
this.state = {
cryptos:["bitcoin","ethereum","stellar","ripple"],
prices:[]
};
this.getPrice = this.getPrice.bind(this);
}
getPrice(){
const cryptos = this.state.cryptos;
console.log(cryptos);
for (var i = 0; i < cryptos.length; i++){
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
axios.get(cryptoUrl)
.then((response) => {
const data = response.data[0];
console.log(data.price_usd);
this.state.prices.push(data.price_usd);
console.log(this.state.prices);
})
.catch((error) => {
console.log(error);
});
}
}
If you want to receive the data in the order of the asynchronous calls you make, you can use Promise.all, that waits until all the promises of an array get executed and are resolved, returning the values in the order they were executed.
const cryptos = ['bitcoin', 'ethereum', 'stellar', 'ripple'];
const arr = [];
for (var i = 0; i < cryptos.length; i++){
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
arr.push(axios.get(cryptoUrl));
}
Promise.all(arr).then((response) =>
response.map(res => console.log(res.data[0].name, res.data[0].price_usd))
).catch((err) => console.log(err));
You could use a closure in the for loop to capture the value of i and use it as the index once the data is returned rather than using push:
getPrice(){
const cryptos = this.state.cryptos;
console.log(cryptos);
for (var i = 0; i < cryptos.length; i++) {
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
(function (x) {
axios.get(cryptoUrl)
.then((response) => {
const data = response.data[0];
console.log(data.price_usd);
var newPrices = this.state.prices;
newPrices[x] = data.price_usd;
this.setState({prices: newPrices});
console.log(this.state.prices);
})
.catch((error) => {
console.log(error);
});
})(i);
}
}

Categories