如何解决角度材质对话框 - 工厂模式
我需要使用角度材质对话框组件创建一个 DRY 模态抽象,并希望使用工厂函数,创建一个新的材质对话框:new Modal(component,config,data)
我想:
- 处理属性配置的模态“模型”
- 处理对话框打开和关闭的模态“服务”
- 传入共享模态组件的任何组件
- “动作”按钮可以作为模板传递到模态中
我想用来创建这些模态/对话框的函数签名:
openModal(): void {
const testData = { name: "dummy name",address: "dummy address" };
this.modalService.createModal(
new Modal(
// component to inject:
ChildComponent,{
// modal options:
title: "the custom title"
},{
// modal config:
data: { item: testData },hasBackdrop: false,autoFocus: false
},{
// modal action "templates":
actionsRight: componentInstance.instance.modalFooterRightRef,actionsLeft: componentInstance.instance.modalFooterLeftRef,}
)
);
}
}
这可以通过材质对话框来完成吗?
这是当前努力的堆栈闪电战:https://angular-dialog-abstraction.stackblitz.io
有一个包含实现的功能模块和一个用于抽象的共享模块。
目前的模态:
√ 打开
√ 注入组件
√ 按预期接收数据
x 按预期工作:没有标题或操作按钮。
模态模型
import { Type } from "@angular/core";
import { MatDialogConfig } from "@angular/material/dialog";
import { ModalOptions,ModalTemplates } from "../interfaces/modal";
import { ModalSizeOptions } from "../enums/modal-size-options.enum";
export class Modal {
static defaultModalOptions: ModalOptions = {
cancel: true,close: false,footer: true,size: ModalSizeOptions.MEDIUM,title: "Attention"
};
static defaultModalConfig: MatDialogConfig = {
data: null,ariaDescribedBy: null,ariaLabel: null,ariaLabelledBy: null,autoFocus: true,backdropClass: null,closeOnNavigation: false,componentFactoryResolver: null,direction: "ltr",disableClose: true,height: "",id: "",maxHeight: null,maxWidth: null,minHeight: null,minWidth: null,panelClass: "",position: { top: "",bottom: "",left: "",right: "" },restoreFocus: true,role: null,scrollStrategy: null,viewContainerRef: null,width: ""
};
static defaultTemplates: ModalTemplates = {
error: null,header: null,content: null,actionsLeft: null,actionsRight: null
};
public component: Type<any>;
public options = Modal.defaultModalOptions;
public dialog = Modal.defaultModalConfig;
public templates: ModalTemplates;
constructor(
component: Type<any>,options?: ModalOptions,dialog?: MatDialogConfig,templates?: ModalTemplates
) {
this.component = component;
this.options = options
? Object.assign({},Modal.defaultModalOptions,options)
: Modal.defaultModalOptions;
this.dialog = dialog
? Object.assign({},Modal.defaultModalConfig,dialog)
: Modal.defaultModalConfig;
this.templates = templates
? Object.assign({},Modal.defaultTemplates,templates)
: Modal.defaultTemplates;
}
}
模态组件
import { Component,ComponentFactoryResolver,OnInit,Input } from "@angular/core";
import { Modal } from "../../models/modal";
@Component({
selector: "app-modal",styleUrls: ["./modal.component.css"],template: `
<div>
<header>
<h1 mat-dialog-title>{{ modal.options.title }}</h1>
<button mat-icon-button mat-dialog-close="true">
<i class="material-icons">clear</i>
</button>
</header>
<mat-dialog-content>
<ng-template #component></ng-template>
</mat-dialog-content>
<div *ngIf="modal.options.footer">
<footer class="flex justify-between w-full">
<div class="modalFooterLeft">
<mat-dialog-actions>
<ng-container
[ngTemplateOutlet]="modal.templates.actionsLeft"
></ng-container>
</mat-dialog-actions>
</div>
<div class="modalFooterRight">
<mat-dialog-actions>
<ng-container
[ngTemplateOutlet]="modal.templates.actionsRight"
></ng-container>
<button
*ngIf="modal.options.cancel"
mat-button
mat-dialog-close
cdkFocusInitial
> Cancel </button>
<button
*ngIf="modal.options.close"
mat-button
mat-dialog-close
> Close </button>
</mat-dialog-actions>
</div>
</footer>
</div>
</div>
`
})
export class ModalComponent implements OnInit {
@Input() public modal: Modal;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,) {}
ngOnInit() {}
}
模态服务
import { Injectable } from "@angular/core";
import { MatDialog,MatDialogConfig } from "@angular/material/dialog";
import { Modal } from "../models/modal";
@Injectable()
export class ModalService {
constructor(public dialog: MatDialog) {}
public createModal(modal?: Modal): any {
return this.openModal(modal.component,modal.dialog);
}
private openModal(component: any,config: MatDialogConfig): any {
return this.dialog.open(component,config);
}
}
将动作按钮作为模板从注入到模态组件中的子组件传递的示例:
<ng-template #actionsRight>
<button
mat-button color="primary"
[disabled]="f.pristine || !f.valid"
[loading]="this.state.loading"
(click)="createItem()"
>Create</button>
</ng-template>
<ng-template #actionsLeft>
<button
mat-button color="primary"
[disabled]="f.pristine || !f.valid"
[loading]="this.state.loading"
(click)="deleteItem()"
>Delete</button>
</ng-template>
非常感谢您的帮助,谢谢。
解决方法
我注意到您直接打开了 ChildComponent
。
this.openModal(modal.component,modal.dialog);
如果您想使用 ModalComponent
作为所有动态创建的对话框的基本包装器,那么您应该打开该组件。
modal.service.ts
this.dialog.open(ModalComponent,{
...modal.dialog,data: modal
});
在这里,我将与对话框相关的选项传递给 MatDialog 以及作为 Modal
的整个 data
模型。此 data
将在 ModalComponent
通过 DI 提供。
modal.component.ts
export class ModalComponent implements OnInit {
constructor(
...
@Inject(MAT_DIALOG_DATA) public modal: Modal
) {}
现在,我们在 ModalComponent 中,我们可以在其中使用低级 Angular API 动态创建传递的 ChildComponent
到 <ng-template #component></ng-template>
:
export class ModalComponent implements OnInit {
@ViewChild("component",{ read: ViewContainerRef,static: true })
componentTarget: ViewContainerRef;
actionsLeft: TemplateRef<any>;
actionsRight: TemplateRef<any>;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,private inj: Injector,@Inject(MAT_DIALOG_DATA) public modal: Modal
) {}
ngOnInit() {
const factory = this.componentFactoryResolver.resolveComponentFactory(
this.modal.component
);
const componentRef = this.componentTarget.createComponent(
factory,null,Injector.create({
providers: [
{
provide: MAT_DIALOG_DATA,useValue: this.modal.dialog.data
}
],parent: this.inj
})
);
之后,您可以在 ChildComponent 中定义为模板的事件操作按钮:
export class ModalComponent implements OnInit {
actionsLeft: TemplateRef<any>;
actionsRight: TemplateRef<any>;
...
ngOnInit() {
...
const componentRef = this.componentTarget.createComponent(
factory,...
);
this.actionsLeft = componentRef.instance.actionsLeftRef;
this.actionsRight = componentRef.instance.actionsRightRef;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。