Jack
Jack

Reputation: 10613

Re-using an RxJS Observable to repeat an asynchronous call?

How can an RxJS Observable emit a new value, if the underlying event stream doesn't emit a new value?

Given an Angular component which uses an async pipe to display a user's name;

export class MyComponent implements OnInit {

  public user$!: Observable<User>;

  constructor(private readonly ms: MyService)

  ngOnInit() {
    this.user$ = this.ms.getUser();
  }
}
<ng-container *ngIf="user$ | async as user; else empty">
  {{ user.name }}
</ng-container>

<ng-template #empty>
  No user here.
</ng-template>

...imagine some time passes and I want to try getting the user again by calling the asynchronous function this.ms.getUser(), how can I do this?

AFAIK, I cannot simply overwrite the Observable $captcha;

export class MyComponent implements OnInit {

  public user$!: Observable<User>;

  constructor(private readonly ms: MyService)

  ngOnInit() {
    this.user$ = this.ms.getUser();
  }

  getUserAgain() {
    // Wrong. This would be a new/different Observable.
    // The UI would not update.
    this.user$ = this.ms.getUser();
  }
}

The service MyService returns an Observable because it's just a thin wrapper around Angular's HttpClient.

Upvotes: 1

Views: 1073

Answers (2)

frido
frido

Reputation: 14089

You could also use repeatWhen:

export class MyComponent implements OnInit {

  public user$!: Observable<User>;
  private repeat$ = new Subject()

  constructor(private readonly ms: MyService) {}

  ngOnInit() {
    this.user$ = this.ms.getUser().pipe(
      repeatWhen(() => repeat$)
    );
  }

  getUserAgain() {
    this.repeat$.next();
  }
}

https://stackblitz.com/edit/eoznkm

Upvotes: 3

maxime1992
maxime1992

Reputation: 23793

I'd recommend to use observables as much as possible and stay in a "reactive mind":

export class MyComponent {
  public refreshUser$: Subject<void> = new Subject();

  public user$!: Observable<User> = this.refreshUser$.pipe(
    startWith(undefined),
    switchMap(() => this.ms.getUser())
  );

  constructor(private readonly ms: MyService) {}

  public getUserAgain() {
    this.refreshUser$.next();
  }
}

Upvotes: 1

Related Questions