Close @angular/material Dialog U

2018-10-30  本文已影响0人  forks1990

By default angular material dialog closed on browser navigation, such as back/forward. Normally it is good, in mobile phone environments, user may want back operation close opened dialog only, keep current angular router entry unchanged.

Disable closeOnNavigation option

const dialogRef = this.dialog.open<YourDialogComponent>(YourDialogComponent, {
    closeOnNavigation: false,
});

Disable closeOnNavigation option tells angular dialog service do not close dialog when user back/forward browser, this happens before @angular/router.

Create @angular/router Deactivate Guard

@Injectable({
  providedIn: 'root',
})
export class CloseDialogOnRouteService implements CanDeactivate<any> {

  constructor(private dialog: MatDialog) { }

  canDeactivate(): Observable<boolean> | Promise<boolean> | boolean {
    if (this.dialog.openDialogs.length === 0) {
      // If current no dialog open, pops current angular router entry normally.
      return true;
    }

    // close and wait all dialogs closed.
    this.dialog.closeAll();
    return this.dialog.afterAllClosed.pipe(first(), map(() => {
      // abort leave current route, user only want to close popup, not current route
      return false;
    }));
  }
}

Fix Bug of @angular/router

A bug of @angular/router https://github.com/angular/angular/issues/13586 if CanDeactivate() returns false, browser history not synced with @angular/router state, to fix, we can re-forward browser history as https://github.com/angular/angular/issues/13586#issuecomment-402250031

@Injectable({
  providedIn: 'root',
})
export class CloseDialogOnRouteService implements CanDeactivate<any> {

  constructor(private dialog: MatDialog,
              private readonly location: Location,
              private readonly router: Router,
  ) { }

  canDeactivate(_: any, currentRoute: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if (this.dialog.openDialogs.length === 0) {
      return true;
    }

    this.dialog.closeAll();
    return this.dialog.afterAllClosed.pipe(first(), map(() => {
      const currentUrlTree = this.router.createUrlTree([], currentRoute);
      const currentUrl = currentUrlTree.toString();
      this.location.go(currentUrl);
      return false;
    }));
  }
}

上一篇下一篇

猜你喜欢

热点阅读