I am creating a Work Item object with linked child Task objects. My function (createWorkItemAndChildren) takes two parameters, the workItem, and an array of Task objects. I want my function to return an array of all ids that are created (work item and tasks).
I have to have the parent ID back from one http POST call (workItemService.createWorkItem) before I can then create the child tasks which use another http POST method on the same service.
I now have the forkJoin in createChildWorkItems returning all of the child ids at once.
How do I refactor this so that there is only one subscribe, and to return the array with parent and child ids together?
createChildWorkItems(parentId, tasks: Task[]): Observable<any> {
return <Observable<number>> forkJoin(
tasks.map(task => <Observable<number>> this.workItemService.createChildWorkItem(parentId, task))
).pipe(zip());
}
createWorkItemAndChildren(workItem, childTasksToSave: Task[]){
var resultArray = [];
this.workItemService.createWorkItem(workItem).subscribe(workItemId => {
var parentId = workItemId;
resultArray.push(parentId);
if (parentId !== null){
this.createChildWorkItems(parentId, childTasksToSave).subscribe((results: number) => {
resultArray.push(results);
this.tfsIdsCreated = resultArray;
});
}
});
}
In your situation child is not good candidate for fork join. but here you should use Async /await. fork join send the request in Async manner but Async/await will wait response of each request when you get response attach that response to parent simple, in Async/await request will be in sequeance just like loop. when all request done, return that object here is link of asyn/await https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/
createWorkItemAndChildTasks(workitem, childTasksToSave: Task[]): any {
this.workItemService.createWorkItem(workitem).subscribe(workItemId => {
var parentId = workItemId;
if (parentId !== null ){
this.tfsIdsCreated.push(parentId);
// now create the children on the workItemForm.
for (let child of childTasksToSave){
//use here Async await when you get response attach to parent
this.workItemService.createChildWorkItem(parentId, child).subscribe(task =>{
if (task !== null){
console.log(' createWorkItem received child taskid: ' + task);
this.tfsIdsCreated.push(task);
}
});
}
}
return this.tfsIdsCreated;
});
}
If you want to do subtasks in parallel — forkJoin is your choice.
Heres a rough example:
createParent().pipe(
// switch from parent stream to forkJoin(...children)
mergeMap(parent =>
// wait for all children to be created
forkJoin(children.map(child => createChild(parent, child))).pipe(
// combine childResults with parent
map(childResults => {
// do operations with parent and all children
parent.childResults = childResults;
// switch back to parent
return parent;
})
)
)
)
.subscribe(parent => {
// ...
})
Note how we subscribe to Observable only once — this is a good practice.
You don't need async await
here.
Hope this helps
Create an array of observables and pass the reference into forkjoin
let observableBatch= [];
for (let child of childTasksToSave){
observableBatch.push(this.workItemService.createChildWorkItem(parentId, child));
}
Observable.forkJoin(observableBatch).subscribe...;
reference: https://stackoverflow.com/a/35676917/6651984
Here's what I ended up doing, which is why I accepted the answer from kos : My tfsIdsCreated array is subscribing to the result, which is providing the list of ids.
createParentAndKids(workItem, childTasksToSave){
this.workItemService.createWorkItem(workItem).pipe(
mergeMap(parentId => {
if (parentId === null){
return of([parentId]);
}
const childTaskObservables$ = childTasksToSave.map(
child => this.workItemService.createChildWorkItem(parentId, child)
);
return forkJoin(childTaskObservables$).pipe(
map(ids => [parentId, ...ids])
);
})
).subscribe(x => this.tfsIdsCreated.push(x));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.