Search code examples
angularrxjsrxjs6rxjs-observablesrxjs-pipeable-operators

Using declarative RxJS, is there a way to pass Observable data to child component from parent component?


I'm using declarative RxJS to return a response object from my back-end service. I am able to grab the data in my bay-page.ts file and display it in my html. However, I want the data to be displayed in my results-page.ts file. I grab the user inputs using Subjects and pass them in a method in my bay-page.ts file, that will then fire off the HTTP request.

But, how do I grab those results and display them in my results-page.html file?

bay-service.ts file:

private bayStartSelectedSubject = new Subject<number>();
  bayStartSelectedAction$ = this.bayStartSelectedSubject.asObservable();

  private bayEndSelectedSubject = new Subject<number>();
  bayEndSelectedAction$ = this.bayEndSelectedSubject.asObservable();


  selectedBayChanged(selectedBayStartNumber: number, selectedBayEndNumber?: number): void {
    this.bayStartSelectedSubject.next(selectedBayStartNumber);
    this.bayEndSelectedSubject.next(selectedBayEndNumber);
  }

  grabHuResponsePOST$ = combineLatest([
    this.bayStartSelectedAction$,
    this.bayEndSelectedAction$
  ])
    .pipe(
      switchMap(([bayStart, bayEnd]) => {
        if (bayEnd == null || bayEnd <= 0) {
          bayEnd = bayStart;
        }
        let huRequest: HuRequest = {
          "centerId": "COS",
          "beginBayId": bayStart,
          "endBayId": bayEnd
        }
        const headers = new HttpHeaders({
          'Content-Type': 'application/json'
        });
        let options = {
          headers: headers
        }
        // this.invalidBay.next(true);
        return this.httpClient.post<HuResponse>(this.HandlingUnitResponseUrl, huRequest, options);
      }),
      tap(showDataPlease => console.log('Bays: ', JSON.stringify(showDataPlease))),
    );

bay-page.ts file:

ngOnInit() {
    this.bayForm = new FormGroup({
      'bayStart': new FormControl(null, [Validators.required]),
      'bayEnd': new FormControl(null, [Validators.required])
    });
    this.bayService.invalidBay$.subscribe(
      value => {
        console.log(value);
        this.invalidBay = value;
      }
    );
    this.bayService.grabHuResponsePOST$.subscribe(p => {

    });
  }

  onSubmit() {
    this.bayService.selectedBayChanged(this.bayForm.get('bayStart').value, this.bayForm.get('bayEnd').value);
    this.navCtrl.navigateForward([`/results/`]);
  }

results-page.ts file:

bayOrBays$ = this.bayService.grabHuResponsePOST$
    .pipe(
      map(response => response.bays),
      catchError(err => {
        this.errorMessageSubject.next(err);
        return EMPTY;
      }),
      tap(showDataPlease => console.log('Bays: ', JSON.stringify(showDataPlease)))
    );

results-page.html file:

<ion-card *ngFor="let bay of bayOrBays$ | async; index as i"
                    class="ion-no-margin">
            <ion-card-header>
              <ion-card-title>Bay {{ bay.bayCode }}</ion-card-title>
              <ion-card-subtitle>{{ bay.shipments.length }} Shipments</ion-card-subtitle>
            </ion-card-header>
          </ion-card>

I am obviously missing something with a subscription because this doesn't work in my results-page.ts file, but it DOES work, if I put it in my bay-page.ts file.


Solution

  • In general, late subscribers will not receive previously emitted values. You can use the shareReplay operator to emit prior values to new subscribers upon subscription:

    grabHuResponsePOST$ = combineLatest([
        this.bayStartSelectedAction$,
        this.bayEndSelectedAction$
      ])
        .pipe(
          switchMap(([bayStart, bayEnd]) => {
            if (bayEnd == null || bayEnd <= 0) {
              bayEnd = bayStart;
            }
            let huRequest: HuRequest = {
              "centerId": "COS",
              "beginBayId": bayStart,
              "endBayId": bayEnd
            }
            const headers = new HttpHeaders({
              'Content-Type': 'application/json'
            });
            let options = {
              headers: headers
            }
            // this.invalidBay.next(true);
            return this.httpClient.post<HuResponse>(this.HandlingUnitResponseUrl, huRequest, options);
          }),
          tap(showDataPlease => console.log('Bays: ', JSON.stringify(showDataPlease))),
          shareReplay(1) // <-----
        );