将 MatDialog 弹出窗口添加到 Angular Root 而不是主体 [英] Add MatDialog popup to Angular Root and not to body

查看:31
本文介绍了将 MatDialog 弹出窗口添加到 Angular Root 而不是主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<头></头><身体><app-library>...</app-library><div class="cdk-overlay-container">...</div></html>

有没有办法将对话框添加到 angular app 元素(在我的例子中)而不是 body 元素?

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

导出类 AppComponent 实现 OnInit {构造函数(...,公共视图引用:ViewContainerRef){}导出类 FilterToggleComponent 实现 OnInit {构造函数(..., 公共对话框: MatDialog, 私有 appRef: ApplicationRef) {}打开过滤器面板(){const viewRef = (this.appRef.components[0].instance as AppComponent).viewRef;const dialogRef = this.dialog.open(FilterPanelComponent, {宽度:'100vw',高度:'100%',面板类:'搜索过滤器面板-模态',视图容器引用:视图引用});}}

解决方案

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

<块引用>

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

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

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

  1. Body -
  2. OverlayContainer -

    </div>
  3. 叠加 -

  4. ComponentPortal -
  5. Component - 我们的 ComponentExampleDialog 组件,其打开方式如下:this.dialog.open(ComponentExampleDialog).

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

<块引用>

所有单独的叠加元素所在的容器元素呈现.

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

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

MatDialogMatSnackbarMatTooltipMatBottomSheet 和所有使用 OverlayContainer 将在此自定义容器中打开.

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

@NgModule({提供者:[{provide: OverlayContainer, useClass: AppOverlayContainer}],//...})导出类 MyModule { }导出类 AppOverlayContainer 扩展 OverlayContainer {受保护的_createContainer():无效{const 容器:HTMLDivElement = document.createElement('div');container.classList.add('app-overlay-container');const 元素: 元素 |null = document.querySelector('#angular-app-root');如果(元素!== 空){element.appendChild(容器);this._containerElement = 容器;}}}

然后,添加以下css:

.app-overlay-container {位置:绝对;z-索引:1000;指针事件:无;顶部:0;左:0;高度:100%;宽度:100%;}.app-overlay-container:empty {显示:无;}

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

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

I have made an Angular 6 app where I have some MatDialog. This works perfectly in development mode.

Now I have to implement this into an existing website (that uses sitecore 9). This works great, except that the dialogs won't open correctly. I've found out that the dialogs are added to the body and not to my angular root DOM element.

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

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

Is there a way to add the dialog to the angular app element (in my case ) and not to the body element?

I've already tried to use the viewContainerRef option matDialog, but this doesn't seem to work:

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
    });
  }
}

解决方案

According to Angular Material docs, viewContainerRef option of MatDialogConfig is:

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.

When inspecting the DOM when a dialog is opened, we'll find the following component hierarchy:

  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 - our ComponentExampleDialog component, which is opened like: this.dialog.open(ComponentExampleDialog).

Now, what we really need to change is the position in the DOM of the OverlayContainer, which, according to docs, is:

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

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

Technically, it is possible to provide a custom overlay container, as described in documentation, but, unfortunately, it is a singleton and creates a potential problem:

MatDialog, MatSnackbar, MatTooltip, MatBottomSheet and all components that use the OverlayContainer will open within this custom container.

If this is not a problem, use the following code, which attaches the overlay container to the element with 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;
    }
  }
}

Then, add the following 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 demo: https://stackblitz.com/edit/angular-wksbmf

Also the following article might be useful, because it contains a similar implementation: https://blog.bbogdanov.net/post/angular-material-overlay-hack-overlay-container/

这篇关于将 MatDialog 弹出窗口添加到 Angular Root 而不是主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆