简体   繁体   中英

async pipe not subscribing to Observable Angular

In Angular (v12) I've got a following component (using dummy variable names):

export class DataDetailsComponent {
    data$: Observable<MyDataModel>;

    constructor(dataService: DataService, route: ActivatedRoute, private router: Router) {
        this.data$ =
            combineLatest([dataService.getDataObservable(), router.events])
                .pipe(
                    filter(([,event]) => event instanceof ActivationEnd),
                    tap(([data, event]) => console.log((<ActivationEnd>event).snapshot.queryParams['id'])),
                    map(([data, event]) => data.filter(c => c.id === (<ActivationEnd>event).snapshot.queryParams['id'])[0]),
                    tap(dataItem => console.log(dataItem))
                );
        this.data$.subscribe(); // console.logs don't work without this
    }
}

And its template:

<div *ngIf="data$ | async as data; else loading">
    <img [src]="data.url" [alt]="data.name">
</div>
<ng-template #loading>Loading...</ng-template>

Data is not being rendered, and the browser console is empty if I don't actually subscribe to the data$ . On the other hand, when I do place this.data$.subscribe(); , console gets correct output, but the view is still empty (hangs on Loading... ).

Can anyone explain what's going on?

can be related to your combineLatest. check to see both observables are emitting data.

CombineLatest definition:

Be aware that combineLatest will not emit an initial value until each observable emits at least one value. This is the same behavior as withLatestFrom and can be a gotcha as there will be no output and no error but one (or more) of your inner observables is likely not functioning as intended, or a subscription is late.

you can use startWith operator to set some initial value for observables.

In the end, it was the router event that was not letting observable complete. Apparently, it works if I move navigation from template to.ts and subscribe to ActivatedRoute.params instead of Router.events .

So, the parent component gets:

navigateToDetails(id: string): void {
    this.router.navigate(['/myRoute', id]);
}

instead of using routerLink in template:

<a [routerLink]="['/myRoute']" [queryParams]="{id: item.id}">

And then, on DataDetailsComponent i can do:

constructor(dataService: DataService, route: ActivatedRoute) {
        this.data$ =
            combineLatest([dataService.getDataObservable(), route.params])
                .pipe(map(([data, params]) => data.filter(c => c.id === params['id'])[0]));
    }

Reasons why are beyond me at this point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM