Home > Net >  Angular async pipe doesn't subscribe
Angular async pipe doesn't subscribe

Time:09-15

In Angular (v12) I've got the component you can see below:
component.html

<h3 *ngIf="userInfo$ | async as userInfo; else loading">{{ userInfo.user.name }}</h3>

<ng-template #loading>
    Loading...
</ng-template>

component.ts

token: string;
userInfo$: Observable<any>
getUserInfo: Subject<string> = new Subject<string>()

constructor(
  private service: Service,
  private route: ActivatedRoute
) { }

ngOnInit(): void {
  this.userInfo$ = this.getUserInfo.pipe(
    mergeMap(token => {
      return this.service.getKey(token).pipe(
        map(res => {
          return {
            user: res.client,
            info: res.info
          }
        })
      );
    }),
    tap((res) => console.log(res))
  )

  this.route.paramMap.subscribe(params => {
    this.token = params.get("token");
    this.getUserInfo.next(this.token);
  });
}

Using the async pipe the user'll get a perpetual loading, while if I this.getUserInfo.pipe(..).subscribe() the right response is logged.
I know that the async pipe subscribes and unsubscribes to the observables, so I expected the ngIf to be truthful.

CodePudding user response:

You have an issue with timing. The problem is that this.getUserInfo.next(this.token) emits before the async pipe subscribes, so you don't receive the emission.

You can simplify your observable chain a bit which would side-step this timing issue.

@Component(...)
class MyComponent() {

    private token$ = this.route.paramMap.pipe(
        map(params => params.get('token')),
        distinctUntilChanged()
    );

    userInfo$ = this.token$.pipe(
        switchMap(token => this.service.getKey(token)),
        map(res => ({
            user: res.client,
            info: res.info
        }))
    );

    constructor(
        private service: Service,
        private route: ActivatedRoute
    ) { }

}

Notice the token is defined as an observable and we defined userInfo$ as an observable that depends on the token$ emissions. There's no need for a separate Subject and a subscription. We also don't need to use ngOnInit.

  • Related