将 MatDialog 弹出窗口添加到 Angular Root 而不是主体

Gre*_* A. 3 angular-material2 angular

我制作了一个 Angular 6 应用程序,其中有一些 MatDialog。这在开发模式下完美运行。

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

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

    <div class="cdk-overlay-container">...</div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

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

我已经尝试使用 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
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

and*_*tor 8

根据 Angular Material文档viewContainerRef选项MatDialogConfig是:

附加组件应该位于 Angular 的逻辑组件树中。这会影响可用于注入的内容以及对话框内实例化组件的更改检测顺序。

这不会影响对话框内容的呈现位置。

打开对话框时检查 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)

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

渲染所有单独覆盖元素的容器元素。

默认情况下,覆盖容器直接附加到文档正文。

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

MatDialogMatSnackbarMatTooltipMatBottomSheet所有使用 的组件都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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,添加以下 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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