3

In my code I have a button which will browse a list of data and open a mat-dialog for each data.

Unfortunately, during the course of the loop, all the mat-dialogs open.

What I would like to happen is that by using the dialogRef.afterClosed() method, depending on the result (true) the next mat-dialog opens or (false) the loop ends.

openDialog(): void {
  this.data.forEach(data => {
    const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
      disableClose: true
    });
    dialogRef.componentInstance.data = data;

    dialogRef.afterClosed().subscribe(result => {
      if (result) {
        // open next mat-dialog
      } else {
        // stop loop
      }
    });
  });
}

<div mat-dialog-actions>
  <button mat-button (click)="_dialogRef.close(true)">Ok</button>
  <button mat-button (click)="_dialogRef.close(false)">Cancel</button>
</div>

StackBlitz Here

How can I do this? I don't know how to go about it.

Thanks for your help.

Quentin
  • 1,865
  • 2
  • 24
  • 40

3 Answers3

3

You can achieve this by rxjs takeWhile

from(this.data)
      .pipe(
        concatMap(x => {
          const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
            disableClose: true
          });

          dialogRef.componentInstance.data = x;

          return dialogRef.afterClosed();
        }),
        takeWhile(Boolean)
      ).subscribe();

See https://stackblitz.com/edit/open-mat-dialogs-one-by-one-after-the-previous-one-is-cl-yqprmt?file=src/app/dialog-overview-example.ts

MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43
  • Thank you very much for your solution, in my original code I am using a list of list ([new StackBlitz](https://stackblitz.com/edit/open-mat-dialogs-one-by-one-after-the-previous-one-is-closed-2?file=src/app/dialog-overview-example.ts)) and I can't seem to set up your solution with a list of list can you help me? – Quentin Oct 21 '20 at 10:11
  • 1
    Just flat the array https://stackblitz.com/edit/open-mat-dialogs-one-by-one-after-the-previous-one-is-cl-k3geac?file=src/app/dialog-overview-example.ts – MoxxiManagarm Oct 21 '20 at 10:18
2

You can achieve this by marking you method as async and awaiting your dialog afterClosed() call, but since awaitworks only with promises you need to convert the Observable to a Promise.

Here is a the solution that works for me

@Component({
  selector: "dialog-overview-example",
  templateUrl: "dialog-overview-example.html",
  styleUrls: ["dialog-overview-example.css"]
})
export class DialogOverviewExample {
  data: any[] = DATA;
  constructor(public dialog: MatDialog) {}

  async openDialog() {

  for(var i =0; i < this.data.length; i++) {
    const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
        disableClose: true
      });
      dialogRef.componentInstance.data = this.data[i];
      var result = await  dialogRef.afterClosed().toPromise();
        if (!result) {
          console.log("Stop loop", result);
          break;
        }
        // else continue the loop

   }
 }
}

Stackblitz Working Demo

Benzara Tahar
  • 2,058
  • 1
  • 17
  • 21
0

I'd suggest to not use an iterator (foreach) (in fact, I would discourage using one), but instead trigger openDialog again in the subscribe if there is still more data to display (queue-like approach). Of course this requires to remove the shown data from the list, but it would also allow for new data being appended to it in the meantime.

Gunnar B.
  • 2,879
  • 2
  • 11
  • 17