0

I have primeng dropdown and two service calls, one making calls to get dropdown options and one to get model binding data. Once I saved the selected value and reload the page, occasionally selected value is not showing. I believe this because of the async nature of the service calls. I guess the model value service call is completed before loading all the dropdown options.

ngOnInit {
   this.drpOption = this.ddOptionSrv.getDrpOption();

   this.ddValueSrv.getDrpModelVal().subscribe(data => {
         this.drValue = data
   })
}

template code:

<p-dropdown [options]="drpOption | async" [(ngModel)]="drValue"></p-dropdown>

How do I make sure dropdown model value loads after dropdown options loads without moving the model service all inside the subscribed method of options call(maintaining the async nature)?

LilRazi
  • 690
  • 12
  • 33

2 Answers2

1

I think you could try this:

this.drpOption$ = this.ddOptionSrv.getDrpOption().pipe(share())

this.drValue$ = this.drpOption$.pipe(
  switchMapTo(this.ddValueSrv.getDrpModelVal()),
)
<p-dropdown [options]="drpOption | async" [(ngModel)]="drValue | async"></p-dropdown>

By using share(), we're adding a Subject between the data producer(the service that provides the options) and the data consumers(the 2 subscribers from | async). With this, ddOptionSrv.getDrpOption() will be called only once and the returned value will be sent to the subscriber from drpOption | async and the subscriber from drValue | async".

And with this you can be sure that the model value loads after options.

Andrei Gătej
  • 11,116
  • 1
  • 14
  • 31
0

One possible solution is to use combineLatest, let's look at a simpler example (imports omitted):

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  data$: Observable<[number, number]>;

  private first$: Observable<number> = interval(1000);
  private second$: Observable<number> = interval(2000);

  ngOnInit(): void {
    this.data$ = combineLatest([this.first$, this.second$]);
  }
}

and the template would be:

<ng-container *ngIf="data$ | async as data">
    <div>first$ = {{ data[0] }}</div>
    <div>second$ = {{ data[1] }}</div>
</ng-container>

This way, the async | data$ would wait for the first emission from both Observables, and on each emit, emits the latest values from each.

In addition, if both Observables emit only once, use forkJoin instead of combineLatest.
You can run the demo in this stackblitz

Tal Ohana
  • 1,128
  • 8
  • 15
  • In my case it is two different data type from two different data source. All I am trying to do is run second data source after first completes or at least call again after first completes without breaking async. – LilRazi Sep 13 '20 at 23:20