I have a question about RxJS. I am creating a web app to manage the members of an association. I want to create a button to "reset" the database of a site. The steps are as follows:
Here's the code I've made, which works, but I know there are a few things wrong. I'm new to RxJS, so I don't quite understand all the principles...
newYear(){
this.amicalisteService.getAmicalistesValides("").subscribe({
// Envoyer un mail à l'ensemble des amicalistes valides
next: amicalistes => {
for(const amicaliste of amicalistes) {
const to = amicaliste.email;
const cc = null;
const subject = "Adhère à l'AEIR";
const body = ""
this.amicalisteService.sendMail(null, to, cc, subject, body).subscribe({
next: response => {
console.log('E-mail envoyé avec succès !', response);
},
error: error => {
console.error('Erreur lors de l\'envoi de l\'e-mail :', error);
}
});
}
},
complete: () => {
// Supprimer amicalistes, photos et cartes amicalistes
this.amicalisteService.getAmicalistes().subscribe(amicalistes => {
for(const amicaliste of amicalistes){
this.amicalisteService.deleteAmicalisteById(amicaliste.id).subscribe();
}
});
this.imageService.getImages("amicaliste").subscribe(images => {
for(const image of images){
this.imageService.deleteImageByName("amicaliste", this.imageService.getImageName(image.toString())).subscribe();
}
});
this.imageService.getImages("pdf").subscribe(pdfs => {
for(const pdf of pdfs){
this.imageService.deleteImageByName("pdf", this.imageService.getImageName(pdf.toString())).subscribe();
}
})
}
//Refresh...
})
}
I've heard it's not good practice to use subscribe() inside subscribe(), but I can't figure out how to do it differently. There are several things I'd like to keep in this code, however. In the complete, the 3 subscribe() run in parallel, if I'm not mistaken. I'd like to keep that. Otherwise, I understand that using a switchMap could help me, but I can't seem to implement it. Can anyone give me some advice?
Thanks you very much !
Here I basically turn a lot of your observables into one, relying mostly on flatMap
(concatMap
when it comes to rxjs) and forkJoin
to combine multiple observables into one which is analogous to Promise.all
for promises.
There's no "monadic" flat map (that I could find) sadly, so we have to map arrays of values to arrays of observable and forkJoin
them.
this.amicalisteService.getAmicalistesValides("").pipe(
concatMap(amicalistes => { // Observable<Amicaliste[]> -> Observable<void[]>
return forkJoin( // Observable<void>[] -> Observable<void[]>
amicalistes.map(amicaliste => { // Amicaliste -> Observable<void>
const to = amicaliste.email;
const cc = null;
const subject = "Adhère à l'AEIR";
const body = ""
return this.amicalisteService.sendMail(null, to, cc, subject, body)
.pipe(tap({
next: response => {
console.log('E-mail envoyé avec succès !', response);
},
error: error => {
console.error('Erreur lors de l\'envoi de l\'e-mail :', error);
}
}));
})
);
}),
// Then, when the above is completed, execute the rest
concatMap(() => forkJoin([
this.amicalisteService.getAmicalistes()
.pipe(
concatMap(amicalistes => {
return forkJoin(amicalistes.map(amicaliste => this.amicalisteService.deleteAmicalisteById(amicaliste.id)));
})
),
this.imageService.getImages("amicaliste")
.pipe(
concatMap(images => {
return forkJoin(
images.map(image => this.imageService.deleteImageByName("amicaliste", this.imageService.getImageName(image.toString())))
)
})
),
this.imageService.getImages("pdf")
.pipe(
concatMap(pdfs => {
return forkJoin(
pdfs.map(pdf => this.imageService.deleteImageByName("pdf", this.imageService.getImageName(pdf.toString())))
)
})
)
])),
);