Angular 关闭浏览器背面的“角度材质”对话框

Angular 关闭浏览器背面的“角度材质”对话框,angular,angular-material,Angular,Angular Material,我正在使用Angular Material(5.0.0)为移动设备创建一个单页Web应用程序。我有一个需要显示对话框的场景。我想允许用户回击以关闭对话框,因为这是移动设备(尤其是Android)上非常常见的行为 当前发生这种情况时,页面将转到上一页。相反,我需要按钮来简单地关闭对话框 关于如何实现这一点有什么想法吗?您可以插入MatDialog服务并调用closeAll方法关闭所有打开的对话框,如下所示 constructor(public dialog: MatDialog) {

我正在使用Angular Material(5.0.0)为移动设备创建一个单页Web应用程序。我有一个需要显示对话框的场景。我想允许用户回击以关闭对话框,因为这是移动设备(尤其是Android)上非常常见的行为

当前发生这种情况时,页面将转到上一页。相反,我需要按钮来简单地关闭对话框


关于如何实现这一点有什么想法吗?

您可以插入
MatDialog
服务并调用
closeAll
方法关闭所有打开的对话框,如下所示

constructor(public dialog: MatDialog) {
         this.dialog.closeAll();
}

作为一种变通方法,您可以添加到根路由。如果对话框打开并关闭,则警卫将取消导航

路由配置:

const rootRoutes: Routes = [{
    path: '',
    canActivateChild: [ CanActivateChildGuard ],
    children: [
        ...
    ]
}];
const rootRoutes: Routes = [{
    path: '',
    canActivateChild: [ CanActivateChildGuard ],
    children: [
        ...
    ]
}];
警卫:

export class CanActivateChildGuard implements CanActivateChild {
    constructor(
        private readonly router: Router,
        private readonly location: Location
    ) {}

    canActivateChild(route: ActivatedRouteSnapshot): boolean {
        if (this.dialog.openDialogs.length > 0) {
            // fix navigation history, see github issue for more details
            // https://github.com/angular/angular/issues/13586
            const currentUrlTree = this.router.createUrlTree([], route);
            const currentUrl = currentUrlTree.toString();
            this.location.go(currentUrl);

            this.dialog.closeAll();
            return false;
        } else {
            return true;
        }
    }
}

您可以收听popstate,然后执行诸如关闭对话框之类的操作

import { HostListener } from '@angular/core';
  @HostListener('window:popstate', ['$event'])
  onPopState(event) {
      this.dialog.closeAll();
}

或使用位置

import {Location} from "@angular/common";

constructor(private location: Location) { }

ngOnInit() {
   this.location.subscribe(x => if back then close dialog);
}

此选项已可用

let dialogRef = dialog.open(DialogExample, {
  height: '400px',
  width: '600px',
  closeOnNavigation: true
});
使用路由更改事件的其他方式:

1。来自应用程序组件

  constructor(router: Router, matDialog: MatDialog) {

    // Close any opened dialog when route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.matDialog.closeAll())
    ).subscribe();
  }
@Component({
  selector: 'example-dialog',
  templateUrl: 'example-dialog.html',
})
export class ExampleDialog {

  constructor(
    public dialogRef: MatDialogRef<ExampleDialog>,
    router: Router
  ) {

    // Close dialog ref on route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.dialogRef.close()),
      take(1),
    ).subscribe();
  }

}
import { Location } from '@angular/common';


constructor(
     private location: Location,
     @Optional() @Inject(MAT_DIALOG_DATA) private person: Person,
     @Optional() private personDialogRef: MatDialogRef<PersonComponent>
) { }
2。来自对话框组件

  constructor(router: Router, matDialog: MatDialog) {

    // Close any opened dialog when route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.matDialog.closeAll())
    ).subscribe();
  }
@Component({
  selector: 'example-dialog',
  templateUrl: 'example-dialog.html',
})
export class ExampleDialog {

  constructor(
    public dialogRef: MatDialogRef<ExampleDialog>,
    router: Router
  ) {

    // Close dialog ref on route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.dialogRef.close()),
      take(1),
    ).subscribe();
  }

}
import { Location } from '@angular/common';


constructor(
     private location: Location,
     @Optional() @Inject(MAT_DIALOG_DATA) private person: Person,
     @Optional() private personDialogRef: MatDialogRef<PersonComponent>
) { }
@组件({
选择器:“示例对话框”,
templateUrl:“example dialog.html”,
})
导出类示例对话框{
建造师(
公共dialogRef:MatDialogRef,
路由器:路由器
) {
//关闭有关管线更改的对话框ref
路由器.事件.管道(
筛选器((事件:RouterEvent)=>NavigationStart的事件实例),
轻触(()=>this.dialogRef.close()),
以(1)为例,
).subscribe();
}
}

我发现,如果在打开模式之前调用history.pushState(),可以通过向后导航“关闭”模式

...
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = false;
dialogConfig.autoFocus = false;
dialogConfig.closeOnNavigation = true;

history.pushState({ foo: "bar" }, "Image", "/currentpage#");    

return this.dialog.open(PictureGalleryComponent, dialogConfig).afterClosed();
...
此外,
[mat dialog close]=“true”
仍然有效,因为散列不会损害当前url


还是有点老套。

每次打开对话框时,都要在url中添加一个查询参数

ex: /test?dlgopen=true
关闭对话框时,从url中删除
dlgopen
,其余内容将由浏览器自动处理。
Home it helps

我也在努力实现这一点,并找到了另一个很好的方法

将对话框设置为自己的路径

这里有一篇很好的文章来解释这一点:

基本步骤:

  • 将子管线添加到要打开对话框的管线
  • 添加到要打开对话框的路由的html中
  • 当用户单击按钮(或等效按钮)并打开对话框时,导航到该子路由
  • 构建子管线组件后,打开该对话框
  • 在新元件中,处理对话框关闭,并导航到父管线

它在我的场景中非常有效。它的好处是对话框是一个路由,因此您甚至可以链接到它,并且在开发和处理对话框时,您不必一直重新打开它

我所做的是利用
MatDialogConfig.closeOnNavigation
选项和浏览器的历史记录

这个想法基本上是在对话框组件初始化时复制浏览器历史记录中的当前状态,并将
true
设置为
closeOnNavigation
属性,这样当用户再次单击浏览器时,对话框关闭,但他仍保持在相同的url中(因为我们在历史记录中复制了它)。这可能不是最好的解决方案,但似乎效果不错

whatever.component.ts
打开对话框:

导出类WhateverComponent{
构造函数(对话框:MatDialog){
}
openDialog(){
this.dialog.open(MyDialog{
closeOnNavigation:正确
}).backdropClick().subscribe(e=>history.back());
}
}
实际的
对话框.component.ts

导出类MyDialog实现OnInit{
构造函数(公共dialogRef:MatDialogRef,
@注入(平台ID)私有平台ID:Object){
}
公共ngOnInit(){
if(isPlatformBrowser(this.platformId)){
history.pushState({},document.getElementsByTagName('title')[0].innerHTML,window.location.href);
}
}
}

我将其包装在
isPlatformBrowser
中,因为我担心它会在SSR中引发一些错误。

我的解决方案是使用closeOnNavigation:false打开所有对话框,然后使用此代码,甚至可以处理重叠的对话框

// push history state when a dialog is opened
dialogRef.afterOpened.subscribe((ref: MatDialogRef<any, any>) => {

  // when opening a dialog, push a new history entry with the dialog id
  location.go('', '', ref.id);

  ref.afterClosed().subscribe(() => {
    // when closing but the dialog is still the current state (because it has not been closed via the back button), pop a history entry
    if (location.getState() === ref.id) {
      history.go(-1);
    }
  });

});

location.subscribe((event: PopStateEvent) => {
  const frontDialog = dialogRef.openDialogs[dialogRef.openDialogs.length - 1];
  // when the user hits back, the state wont equal the front popup anymore, so close it
  // when a popup was closed manually, the state should match the underlying popup, and we wont close the current front
  if (frontDialog && location.getState() !== frontDialog.id) {
    frontDialog.close();
  }
});
//打开对话框时推送历史记录状态
dialogRef.AfterOpen.subscribe((ref:MatDialogRef)=>{
//打开对话框时,按下带有对话框id的新历史记录条目
位置。go(“”,,,参考id);
参考afterClosed().订阅(()=>{
//关闭但对话框仍为当前状态时(因为尚未通过“后退”按钮关闭),弹出历史记录条目
if(location.getState()==ref.id){
历史。go(-1);
}
});
});
位置.订阅((事件:PopStateEvent)=>{
const frontDialog=dialogRef.openDialogs[dialogRef.openDialogs.length-1];
//当用户回击时,状态不再等于前面的弹出窗口,所以关闭它
//手动关闭弹出窗口时,状态应与基础弹出窗口匹配,并且我们不会关闭当前前端
if(frontDialog&&location.getState()!==frontDialog.id){
frontDialog.close();
}
});

也许这种方法会对你有所帮助

此代码进入实际对话框组件内部,在这种情况下PesonComponent

  constructor(router: Router, matDialog: MatDialog) {

    // Close any opened dialog when route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.matDialog.closeAll())
    ).subscribe();
  }
@Component({
  selector: 'example-dialog',
  templateUrl: 'example-dialog.html',
})
export class ExampleDialog {

  constructor(
    public dialogRef: MatDialogRef<ExampleDialog>,
    router: Router
  ) {

    // Close dialog ref on route changes
    router.events.pipe(
      filter((event: RouterEvent) => event instanceof NavigationStart),
      tap(() => this.dialogRef.close()),
      take(1),
    ).subscribe();
  }

}
import { Location } from '@angular/common';


constructor(
     private location: Location,
     @Optional() @Inject(MAT_DIALOG_DATA) private person: Person,
     @Optional() private personDialogRef: MatDialogRef<PersonComponent>
) { }
}

现在,触摸移动设备(如Android)上的后退按钮,观察URL将如何从
/person/123
更改为
person
,对话框将关闭

如果使用关闭对话框的按钮,则关闭后的
也会将URL更改回
/person


祝你好运

关于下面的解决方案,我的灵感来自答案,经过改进和简化

 {path: "edit/:id", component: HeroesEditComponent, canDeactivate: [CloseModalOnBrowserBackIfNecessaryDeactivateGuard]}