2

Imagine a list of users displayed in an Angular component. I inject my service and subscribe to it in my template.

I also have a dialog where you can add users to my table. After adding and closing my dialog, I want to refresh the table via re-triggering the service call.

component:

export class UserComponent implements OnInit {
  public users$!: Observable<User[]>;

  constructor(
    public dialog: MatDialog,
    private userService: UserService,
  ) {}

  public ngOnInit() {
    this.users$ = this.userService
      .getAllUsers$()
      .pipe(take(1));
  }

  public openAddUserDialog() {
    this.dialog
      .open(AddUserDialogComponent)
      .afterClosed()
      .subscribe(() => {
        // TODO re-trigger observable here?
      });
  }
}

template:

<p *ngFor="user of users$ | async">{{ user.name }}</p>

How do I re-trigger the service call in the afterClosed() function from the dialog? I do not want to subscribe this in my subscribe.

I believe there must be a pattern to join the return value of the getAllUsers$() with another Observable and push something there and then re-trigger the process.

Florian Leitgeb
  • 15,657
  • 6
  • 31
  • 40
  • 2
    Is the answer of this question good enough for you ? https://stackoverflow.com/a/59846491/9880876 they use a subject to retrigger the call to the API – bmtheo Jan 22 '20 at 15:17
  • I was about to share the same haha (I'm the author). Florian, the link above is definitely the way to go (with you current architecture). If you had a store (for example with ngrx) it might be easier to deal with but that's another topic :) – maxime1992 Jan 22 '20 at 15:30
  • Thanks, posting this answer helped me a lot. But I went with the `reapeatWhen()` approach, as I think it is more intuitiv and readable. It also feels that the operator is made for this scenario. – Florian Leitgeb Jan 23 '20 at 09:51

2 Answers2

1

I ended up using the reapeatWhen() operator, as it is the most intuitiv and descriptive way in my opinion.

Adjustet my answer so the list of users gets only refetched, when a user was really added

export class UserComponent implements OnInit {
  public users$!: Observable<User[]>;

  private refetchUsers$ = Subject();

  constructor(
    public dialog: MatDialog,
    private userService: UserService,
  ) {}

  public ngOnInit() {
    this.users$ = this.userService
      .getAllUsers$()
      .pipe(
        take(1),
        repeatWhen(() => refetchUsers$),
      );
  }

  public openAddUserDialog() {
    this.dialog
      .open(AddUserDialogComponent)
      .afterClosed()
      .pipe(filter((userAdded) => userAdded))
      .subscribe(() => {
        this.refetchUsers$.next();
      });
  }
}
Florian Leitgeb
  • 15,657
  • 6
  • 31
  • 40
0

Don't know if it's a best practise, but could you try this :

export class UserComponent implements OnInit {
  public users$!: Observable<User[]>;

  constructor(
    dialog: MatDialog,
    private userService: UserService,
  ) {}

  ngOnInit() {
    this.getUsers();
  }

  openAddUserDialog() {
    this.dialog
      .open(AddUserDialogComponent)
      .afterClosed()
        .pipe(
          filter(user => !!user), // Avoid closing modal without creating a new user
          tap(() => this.getUsers()))
      .subscribe();
  }

  getUsers() {
    this.users$ = this.userService
      .getAllUsers$()
      .pipe(take(1));
  }
}
Emilien
  • 2,701
  • 4
  • 15
  • 25
  • I do not get your approach. You are setting the `users$` class variable with a cold Observable everytime you close it. Did you try this out? I do not believe this works. – Florian Leitgeb Jan 22 '20 at 21:24
  • @FlorianLeitgeb I didn't use Dialog to achieve this on a Stackblitz, but I tried to reproduce and it's working. [See here](https://stackblitz.com/edit/angular-q7l93b) – Emilien Jan 23 '20 at 08:55
  • We agreed on the fact that it's better with Subject :) – Emilien Jan 23 '20 at 08:56