将 MatDialog 弹出窗口添加到 Angular 根而不是正文
Add MatDialog popup to Angular Root and not to body
我制作了一个 Angular 6 应用程序,其中有一些 MatDialog。这在开发模式下完美运行。
现在我必须将其实施到现有网站(使用 sitecore 9)中。
这很好用,只是对话框无法正确打开。
我发现对话框被添加到正文而不是我的 angular 根 DOM 元素。
<html>
<head></head>
<body>
<app-library>...</app-library>
<div class="cdk-overlay-container">...</div>
</body>
</html>
有没有办法将对话框添加到 angular app 元素(在我的例子中)而不是 body 元素?
我已经尝试使用 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 Materialdocs,MatDialogConfig
的viewContainerRef
选项是:
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 时,我们会发现以下组件层次结构:
Body
- <body>
OverlayContainer
- <div class="cdk-overlay-container"></div>
Overlay
- <div id="cdk-overlay-{id}" class="cdk-overlay-pane">
ComponentPortal
- <mat-dialog-container></mat-dialog-container>
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 6 应用程序,其中有一些 MatDialog。这在开发模式下完美运行。
现在我必须将其实施到现有网站(使用 sitecore 9)中。 这很好用,只是对话框无法正确打开。 我发现对话框被添加到正文而不是我的 angular 根 DOM 元素。
<html>
<head></head>
<body>
<app-library>...</app-library>
<div class="cdk-overlay-container">...</div>
</body>
</html>
有没有办法将对话框添加到 angular app 元素(在我的例子中)而不是 body 元素?
我已经尝试使用 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 Materialdocs,MatDialogConfig
的viewContainerRef
选项是:
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 时,我们会发现以下组件层次结构:
Body
-<body>
OverlayContainer
-<div class="cdk-overlay-container"></div>
Overlay
-<div id="cdk-overlay-{id}" class="cdk-overlay-pane">
ComponentPortal
-<mat-dialog-container></mat-dialog-container>
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/