angular - 将 MatDialog 弹出窗口添加到 Angular Root 而不是 body

标签 angular angular-material2

我制作了一个 Angular 6 应用程序,其中有一些 MatDialog。这在开发模式下非常有效。

现在我必须将其实现到现有网站(使用 sitecore 9)中。 这很好用,只是对话框无法正确打开。 我发现对话框被添加到正文而不是我的 Angular 根 DOM 元素。

<html>
  <head></head>
  <body>
    <app-library>...</app-library>

    <div class="cdk-overlay-container">...</div>
  </body>
</html>

有没有办法将对话框添加到 Angular 应用程序元素(在我的例子中)而不是主体元素?

我已经尝试过使用 viewContainerRef 选项 matDialog,但这似乎不起作用:

export class AppComponent implements OnInit {
  constructor(..., public viewRef: ViewContainerRef) {
}

export class FilterToggleComponent implements OnInit {
  constructor(..., public dialog: MatDialog, private appRef: ApplicationRef) {}
  openFilterPanel() {
    const viewRef = (this.appRef.components[0].instance as AppComponent).viewRef;
    const dialogRef = this.dialog.open(FilterPanelComponent, {
      width: '100vw',
      height: '100%',
      panelClass: 'search-filter-panel-modal',
      viewContainerRef: viewRef
    });
  }
}

最佳答案

根据 Angular Material docs , viewContainerRef MatDialogConfig 的选项是:

Where the attached component should live in Angular's logical component tree. This affects what is available for injection and the change detection order for the component instantiated inside of the dialog.

This does not affect where the dialog content will be rendered.

在打开对话框时检查 DOM 时,我们会发现以下组件层次结构:

  1. Body - <body>
  2. OverlayContainer - <div class="cdk-overlay-container"></div>
  3. Overlay - <div id="cdk-overlay-{id}" class="cdk-overlay-pane">
  4. ComponentPortal - <mat-dialog-container></mat-dialog-container>
  5. Component - 我们的 ComponentExampleDialog组件,打开方式如下:this.dialog.open(ComponentExampleDialog) .

现在,我们真正需要改变的是 OverlayContainer 在 DOM 中的位置, 根据docs , 是:

the container element in which all individual overlay elements are rendered.

By default, the overlay container is appended directly to the document body.

从技术上讲,可以提供自定义 覆盖容器,如documentation 中所述。 , 但不幸的是,它是一个单例 并且会产生一个潜在的问题:

MatDialog , MatSnackbar , MatTooltip , MatBottomSheet以及所有使用 OverlayContainer 的组件将在此自定义容器中打开。

如果这不是问题,请使用以下代码,它将覆盖容器附加到带有 id="angular-app-root" 的元素上:

@NgModule({
  providers: [{provide: OverlayContainer, useClass: AppOverlayContainer}],
 // ...
})
export class MyModule { }

export class AppOverlayContainer extends OverlayContainer {

  protected _createContainer(): void {
    const container: HTMLDivElement = document.createElement('div');
    container.classList.add('app-overlay-container');

    const element: Element | null = document.querySelector('#angular-app-root');
    if (element !== null) {
      element.appendChild(container);
      this._containerElement = container;
    }
  }
}

然后,添加以下CSS:

.app-overlay-container {
  position: absolute;
  z-index: 1000;
  pointer-events: none;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
}

.app-overlay-container:empty {
  display: none;
}

Stackblitz 演示:https://stackblitz.com/edit/angular-wksbmf

以下文章也可能有用,因为它包含类似的实现: https://blog.bbogdanov.net/post/angular-material-overlay-hack-overlay-container/

关于angular - 将 MatDialog 弹出窗口添加到 Angular Root 而不是 body,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52763285/

相关文章:

angular-material2 - 角度 Material 对话框中的单选按钮焦点

angular-material2 - Angular material 2 数据表 Error Uncaught Error : Template parse errors:

angular - 嵌入式模板上的任何指令均未使用属性绑定(bind) matHeaderRowDef

angular - 如何设置 ngx-charts 折线图中 x 轴和 y 轴标签颜色的格式

javascript - Angular http.get() 检测调用超时

angular - 在 Angular 9 构建过程中删除未使用的 CSS

angular - 在 md-sidenav-layout 中时,md-toolbar 可以固定在顶部吗?

angular - 将 @Output 与 "angular 4.0"的 <router-outlet> 一起使用

mongodb - angular 2 + meteor 中已经有一个名为 "collection"的集合

javascript - 卡在 Angular 2 的 Angular Material 中的 MdSnackBar 的可观察循环中