Search code examples
htmlangularasynchronouspublish-subscribe

Angular nested subscribe code not working as expected


My task consists of 2 steps. First step is to retrieve some id data from firestore. Second is to retrieve name data based on the data retrieved in the first step. So I used 1 subscribe for each step. In the code where I am doing console.log() the correct result appears however when the webpage loads the dropdownlist is empty.

this.MessagingService.recieveGetClient().subscribe(idData => {
  this.dropdownList = [];
  idData.map((id: string, i: number) => {
    this.VehicleService.getOwnerInfo(id).subscribe(namedata => {
      this.dropdownList.push({ item_id: `${i}`, doc_id: namedata['username'] });
      console.log("this.dropdownList:",this.dropdownList);
    });
  });
});

Below is the HTML code. If I get rid of the second subscribe and use id instead of username for dropdownList then it works. But I need to use the username.

<ng-multiselect-dropdown
    [settings]="dropdownSettings"
    [placeholder]="'Send Message to...'"
    [data]="dropdownList"
    [(ngModel)]="selectedItems"
    (onSelect)="onItemSelect()"
    (onSelectAll)="onSelectAll($event)"
    (onDeSelect)="onItemDeSelect()"
    (onDeSelectAll)="onDeSelectAll()"
>
</ng-multiselect-dropdown>

Solution

  • Since it's multiple subscriptions and mapping data, it's best to use an observable to pipe off the different sources with a switchMap, like this:

    this.dropdownList$  = this.MessagingService.receiveGetClient()
    .pipe(switchMap(id => this.VehicleService.getOwnerInfo(id).pipe(map(nameData => ({id, doc_id: nameData.username})))
    ));
    

    In the template, you can use an async pipe to unwrap the value

    [data]="dropdownList$ | async"
    

    Note that because the async pipe will subscribe, you don't need to manually subscribe in the component or worry about unsubscribing.

    Hope this helps!