Reputation: 818
I have an angular entity Z
which one of its properties is a list of another entity Y
, I need to delete entity Z
and when I do it I need to delete the list of entity Y
inside of it. The problem is that first I need to delete all the Y
values and then delete the Z
due to FK problems on database. My method is the following:
onDelete(id: number, name: string, Y: Y[]) {
this.deleteYInZ(Y);
this.ZService.deleteZ(this.selectedSecuritySubject.value, id).subscribe(() => {
this.getAllZ();
}
}
and the deleteYInZ
is:
deleteYInZ(Y: Y[]) {
for (const Yentity of Y) {
this.targetService.deleteTarget(this.selectedSecuritySubject.value, Yentity .ID).subscribe(() => {
});
}
}
I have an async
problem here I tried to do async deleteYInZ
and then put an await
on the onDelete method but It's not working
How can I do to first delete all the Y
and after it finishes delete all the Z
?
Upvotes: 0
Views: 6683
Reputation: 1131
Whenever you have for loops or for each loops with an asynchronous action within them within Javascript, they can throw YOU for a loop instead because they don't exactly behave as most expect -- in most cases, the for loop will complete before the asynchronous actions. I would try something like the following (hopefully at least gets you on the right track):
async onDelete(id: number, name: string, Y: Y[]) {
await this.deleteYInZ(Y);
...
}
async deleteYInZ(Y: Y[]) {
await this.asyncForEach(Y, async (Yentity) => {
await this.targetService.deleteTarget(this.selectedSecuritySubject.value, Yentity.ID);
});
}
async asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
On an aside, you should not be subscribing to everything, especially with inner observable loops, but rather piping it and returning observables using tools like mergeMap (you should make it so that only the caller is subscribing, otherwise you may run into other issues, like weird behavior and memory leaks). That is beyond the scope of this question, but I would look more into rxjs and how to do this in a reactive methodology.
Upvotes: 0
Reputation: 81
try use a promise in this flow, using the then operator in delete function.
so only after the for
termination will it return
onDelete(id: number, name: string, Y: Y[]) {
this.deleteYInZ(Y).then(_ => {
this.ZService.deleteZ(this.selectedSecuritySubject.value, id).subscribe(() => {
this.getAllZ();
});
}
deleteYInZ(Y: Y[]) {
return Promise.resolve().then(function () {
for (const Yentity of Y) {
this.targetService.deleteTarget(this.selectedSecuritySubject.value,Yentity.ID).subscribe(() => {
});
}
})
}
Upvotes: 1
Reputation: 201
This can be done by using an external async/await function or you can use the new for...of iteration (as you're doing right now).
for (const theY of Y) {
await yourDeleteFunction(theY);
}
But, honestly, if you have access to the BE, I'd change your approach a little bit. Instead of doing a forEach or for...of or whatever other iteration, you should use a bulkDelete. This way you will save a few request to your BE and a few DB executions :). Something like this:
deleteZInz(id: number, name: string, items: Y[]) {
this.deleteYInz(items)
.subscribe(result => {
this.ZService.deleteZ(...etc);
});
}
deleteYInz(items: Y[]): Observable<yourReturnType> {
return this.targetService.deleteBulk(
this.selectedSecuritySubject.value,
items.map(item => item.id),
);
}
This way, lets say you have a MySQL DB, you will be doing just 1 delete by doing a where in (1, 2, 3, 4, n) instead of doing 1 request and 1 delete per each of your Y items.
Upvotes: 1