简体   繁体   中英

RxJs Angular 7 HttpClient multiple POST with forkJoin remove second subscribe?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM