Search code examples
angularrxjsobservable

call multiple http and return multiple observables


I am trying to call multiple http and combine multiple observables to one but always emit only the last one. I have input field with formcontrol ctl and when input a keyword, search for customer, item and task.

    ctl: FormControl = new FormControl();

    this.list$ = this.ctl.valueChanges
      .pipe(
        debounceTime(100),
        startWith(null),
        mergeMap((res: any) => {
          if (res) {
            this.keyword = res;
            return forkJoin([this.dataService.searchCustomer(res),
                             this.dataService.searchItem(res),
                             this.dataService.searchTask(res)]);
          } else {
            return of([]);
          }    
        })
      );

And I tried

<input  type="text" placeholder="Enter title" aria-label="Number" matInput [formControl]="ctl"
             [matAutocomplete]="auto" >
      <mat-autocomplete #auto="matAutocomplete">
          <ng-container *ngFor="let list of list$ | async ; let i = index">
            <mat-option *ngFor="let option of list | async" >
              {{option.id}}
            </mat-option>
          </ng-container>
      </mat-autocomplete>

But I get error You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.

How can I return multiple observables and subscribe to display?


Solution

    1. After forkJoin, with map operator to combine the arrays from each observable into single array.
    import {
      debounceTime,
      forkJoin,
      map,
      Observable,
      of,
      startWith,
      mergeMap,
    } from 'rxjs';
    
    this.list$ = this.ctl.valueChanges.pipe(
      debounceTime(100),
      startWith(null),
      mergeMap((res: any) => {
        if (res) {
          this.keyword = res;
          return forkJoin([
            this.dataService.searchCustomer(res),
            this.dataService.searchItem(res),
            this.dataService.searchTask(res),
          ]).pipe(map(([a, ...b]) => a.concat(...b)));
        } else {
          return of([]);
        }
      })
    );
    
    1. Modify the view part to render each option object in the list$ observable.
    <mat-autocomplete #auto="matAutocomplete">
      <ng-container *ngFor="let option of list$ | async ; let i = index">
        <mat-option>
          {{option.id}}
        </mat-option>
      </ng-container>
    </mat-autocomplete>
    

    Demo @ StackBlitz