0
votes

I have a question. I am starter in RxJS and didn't find answer yet network. Thus, would like to ask you. What I need: I extract a Id from ActivatedRoute and then (on my mind, however not sure) create 2 streams. 1st - will download realted parts for item, and 2nd - will download main details. Next requests depends on this details.
I perform this logic with code below. Everything works well. However, I am afraid that I wrote not good code as it should be. Maybe somebody could correct me and explain my mistakes. I have some straight questions I put it here and mark with number in code for easier navigation.

1) When I create 2 separate streams it launches router$ twice. Is it important? How I could launch it once and then separate on 2 streams?

2) forkJoin. Acctually I don't need to wait untill all request will be executed. I didn't find proper operator which will emit values without waiting another. And it was good if error on any request does not cancel all another. Is there some another suitable operator?

3) switchMap or mergeMap? I know that switchMap cancel previous request, but still I don't know which operator is preferable for it.

4) I decided at the end to merge this into 1 subscription and in ngOnDestroy unsubscribe. But maybe it would be better to use subscribe instead of operator map and unsubscribe from each separatly?

Thank you in advance for you answer. If you have any another idea or remarks please shoot. I will be very appriciate!

router$ =  this.aRoute.paramMap.map(params => +params.get('id'));        // <----  1

ngOnInit() {
  this.details$ = this.router$.mergeMap(id => {                           // <---- 3
    return this.claimSvc.getClaimDetails(id);
  }).do(details => {
    this.currentDetails = details;
    .... // some borring things            
  }).switchMap(details => {                                              // <---- 3
    return  Observable.forkJoin(                                          // <--- 2
      this.claimSvc.getDocuments(details.date....),
      this.claimSvc.getHolders(details.date...),
      this.claimSvc.getSubTypes(details.date...),
      this.claimSvc.getCategories(details.date...)
    )
  }).map(([documents, holders, subtypes, categories]) => {
    this.documents = documents;
    this.holders = holders;
    this.subTypes = subtypes;
    this.categories = categories;
  });

  this.claimParts$ = this.router$.switchMap(id => {                     // <---- 3
    return Observable.forkJoin(                                         //  < ------ 2
      this.claimSvc.getAttributes(id), 
      this.claimSvc.getParties(id),
      this.claimSvc.getClaimObjects(id),
      this.claimSvc.getClaimInsurances(id),
      this.claimSvc.getClaimPayments(id)
    )
  }).map(([Attribute, Parties, Objects, Insurances, Payments]) => {
    this.attributes = Attribute;
    this.parties = Parties;
    this.objects = Objects;
    this.insurances = Insurances;
    this.payments = Payments;
  });

  this.subscription = Observable.merge(this.claimParts$, this.claimDetails$).subscribe();  // <----  4
}
1

1 Answers

0
votes
  1. Create a guard
  2. Inside guard, have 2 functions each firing one request and returning Observable from it
  3. In guards CanActivate method do something like this:

.

FireFirstRequest(): Observable<boolean> {
///get your data and save it somewhere (shared service or something)
///and return Observable<boolean> (true) when done
}

FireSecondRequest(): Observable<boolean> {
///get your data and save it somewhere (shared service or something)
///and return Observable<boolean> (true) when done
}

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
   const combined = Observable.zip(
   this.FireFirstRequest(),
   this.FireSecondRequest(),
   (a, b) => a && b
   );

   return combined;
}
  1. In route definitions, use the guard to protect that route/component

Observable.zip makes sure it returns true only when each inner Observable has emmited and they are both true (a&&b).