fetch data with async pipe when view is ready

Viewed 368

I have a basic table component. The user is able to reload and filter the data. For those two actions I use Subjects.

private fetchFromServer$ = new Subject<void>();
private filter$ = new Subject<void>();

The data fetch will then be switched into an observable:

private externalData$ = this.fetchFromServer$.pipe(
  switchMap(() => this.loadFromServer())
);

Afterwards the observable (with the external data) will be combined with the filter-subject, like this:

data$ = combineLatest([this.externalData$, this.filter$]).pipe(
  switchMap(([externalData]) => this.search(externalData))
);

here is the basic view:

<div *ngIf="data$ | async as data">
  {{data |json}}
</div>

<button (click)="reload()">reload</button>
<button (click)="filter()">filter</button>

But this implementation has some drawbacks yet:

The table won't be displayed initially. combineLatest needs at least one emit of externalData$ and filter$. If both buttons "reload" and "filter" gets clicked, the table data will be displayed. But that's not the problem, because I want to display the table initially and as a result I want to call

fetchFromServer$.next()
filter$.next();

on the correct position.

But exactly here is my problem. Where to call those two lines? If I put them in the ngOnInit()-method, the data won't be shown. I guess, because the async pipe subscribes to it later.

Or should the Observable be a hot observable with replaying the last emit? But I have no clue how to do that and furthermore it must be unsubscribed in the ngOnDestroy()-method?

Should it be placed into the ngAfterViewInit() lifecycle hook? Then it works, but I get he famous "Expression has changed after it was checked" error.

Here is the sample project: https://stackblitz.com/edit/angular-sl3kku

1 Answers
Related