Angular CLI:嵌套材质对话框的假阳性循环依赖项警告?
我的Angular 8应用程序使用一个服务类,该类根据许多不同的组件类型包装Angular Material对话框实现并呈现对话框。以下是它的简化版本:Angular CLI:嵌套材质对话框的假阳性循环依赖项警告?,angular,typescript,angular-material,angular-cli,circular-dependency,Angular,Typescript,Angular Material,Angular Cli,Circular Dependency,我的Angular 8应用程序使用一个服务类,该类根据许多不同的组件类型包装Angular Material对话框实现并呈现对话框。以下是它的简化版本: @Injectable() export class MyService { renderDialogTypeOne() { // implementation here calls // matDialog.open(TypeOne) } renderDialogTypeTwo() {
@Injectable()
export class MyService {
renderDialogTypeOne() {
// implementation here calls
// matDialog.open(TypeOne)
}
renderDialogTypeTwo() {
// implementation here calls
// matDialog.open(TypeTwo)
}
}
由于该服务类引用它呈现的类型,因此它对这些类型具有依赖性。但是,其中一个呈现类型(TypeTwo
如下)也将上述服务注入其构造函数,以便它可以启动自己的TypeOne
对话框:
export class TypeOne {
}
export class TypeTwo {
contructor(private service: MyService) { }
showNestedDialog() {
this.service.renderDialogTypeOne();
}
}
因此,服务类和TypeTwo
之间似乎存在循环依赖关系。我知道我可以通过将服务类拆分为多个部分并只引用给定上下文中所需的部分来解决这个问题,但仅仅为了解决编译器警告而拆分类似乎是不对的
这真的是循环依赖吗?如果是这样的话,那么在许多其他场景中,两个实体之间存在鸡/蛋关系,难道不存在同样的问题吗
除了禁用Angular的循环相关性警告之外,还有什么合理的解决方案吗?的Angular Material源代码显示使用
注射器来实例化要在对话框中显示的组件
因此,循环依赖项警告似乎是误报
可通过更新angular.json禁用循环依赖项警告。遗憾的是,此选项不适用于每个文件
angular.json
变通办法
下面的解决方案允许嵌套调用,其中组件类型为对话框的对话框可以打开组件类型为对话框警告组件的对话框,反之亦然
例子
从“…”导入{DialogService,DialogYesNoComponent,DialogWarningComponent}
出口一类{
构造函数(私有对话服务:对话服务){}
showYesNoDialog(){
const dialog_question=“是否继续?”;
const dialog\u ref:MatDialogRef=
此.dialog\u service.open\u yes\u no\u对话框({
问题:对话(问题),,
标题:“确认”,高度:“300px”})
对话框\u ref.afterClosed().订阅(
(选项:“是”|“否”)=>{
如果(选项==“是”){
//继续
}否则{
//打开嵌套对话框
这个.showWarningDialog(“停止程序”);
}
}
)
}
显示警告对话框(警告:字符串){
...
}
}
对话服务
从'@angular/core'导入{ElementRef,Injectable};
从“@angular/material”导入{MatDialog,MatDialogRef};
从“./dialog warning/dialog warning.component”导入{DialogWarningComponent};
从“./dialog yes no/dialog-yes-no.component”导入{DialogYesNoComponent};
@可注射()
导出类对话框服务{
构造函数(公共对话框:MatDialog){}
公开打开是否对话框({问题,标题='Confirm',是按钮\u first=true,
has_background=false,高度=250px,宽度=350px}:
{
问题:字符串,标题?:字符串,是按钮\u优先?:布尔,有背景?:布尔,
高度?:字符串,宽度?:字符串
}):MatDialogRef{
const dialog\u ref=this.dialog.open(DialogYesNoComponent{
自动对焦:对,
backdropClass:“cdk覆盖透明背景”,
closeOnNavigation:正确,
disableClose:false,
HasBackground:has_background,
高度:高度,,
宽度:宽度,
数据:{问题:问题,标题:标题,是按钮首先:是按钮首先}
})
返回对话框\u ref
}
公共打开警告对话框(){
{警告,标题='警告',
has_background=false,高度=250px,宽度=350px}:
{
警告:字符串,标题?:字符串,有背景?:布尔,
高度?:字符串,宽度?:字符串
}):MatDialogRef{
const dialog_ref=this.dialog.open(DialogWarningComponent{
自动对焦:对,
backdropClass:“cdk覆盖透明背景”,
closeOnNavigation:正确,
disableClose:false,
HasBackground:has_background,
高度:高度,,
宽度:宽度,
数据:{警告:警告,标题:标题}
})
返回对话框\u ref
}
}
对话框是非组件
从'@angular/core'导入{Component,Inject};
从“@angular/material/DIALOG”导入{MatDialogRef,MAT_DIALOG_DATA};
导出接口对话框选项{
问题:字符串
标题:字符串
是按钮第一个:布尔值
}
@组成部分({
选择器:'对话框是否',
templateUrl:'。/dialog-yes-no.component.html',
样式URL:['./dialog-yes-no.component.css']
})
导出类对话框YesNoComponent{
构造函数(公共对话框\u ref:MatDialogRef,
@注入(MAT_DIALOG_DATA)公共选项:YesNoDialogOptions{}
}
对话框警告组件
从'@angular/core'导入{Component,Inject};
从“@angular/material/DIALOG”导入{MatDialogRef,MAT_DIALOG_DATA};
导出接口警告对话框选项{
警告:字符串
标题:字符串
}
@组成部分({
选择器:“对话框警告”,
templateUrl:'./对话框warning.component.html',
样式URL:['./对话框警告.component.css']
})
导出类对话框警告组件{
构造函数(公共对话框\u ref:MatDialogRef,
@注入(MAT_DIALOG_DATA)公共选项:WarningDialogOptions{}
}
我正试图找到一种不需要额外细节的推理方法。通常,循环依赖性问题意味着您的体系结构可以得到改进。相互需要的元素通常可以重新排列,以便它们都有一个共同的需求。例如,在您的实现中,可以renderDialogTypeTwo
passrenderDialogTypeOne
到新对话框实例?循环依赖项错误可保护您免受spagheti代码的攻击。是的,我也遇到过这种情况,以一致的方式重写您的应用程序将对您有很大帮助。为什么不从父级扩展您的对话框类型?谢谢您的建议
....
"defaults": {
....
"build": {
"showCircularDependencies": false
}
}
import { DialogService, DialogYesNoComponent, DialogWarningComponent } from '...'
export class TypeOne {
constructor(private dialog_service: DialogService) { }
showYesNoDialog() {
const dialog_question = "Would you like to continue?";
const dialog_ref: MatDialogRef<DialogYesNoComponent> =
this.dialog_service.open_yes_no_dialog({
question: dialog_question,
title: 'Confirm', height: '300px' })
dialog_ref.afterClosed().subscribe(
(choice: 'yes' | 'no') => {
if (choice === 'yes') {
// Continue
} else {
// Open Nested Dialog
this.showWarningDialog("Stopping the program.");
}
}
)
}
showWarningDialog(warning: String) {
...
}
}
import { ElementRef, Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material';
import { DialogWarningComponent } from './dialog-warning/dialog-warning.component';
import { DialogYesNoComponent } from './dialog-yes-no/dialog-yes-no.component';
@Injectable()
export class DialogService {
constructor(public dialog: MatDialog) { }
public open_yes_no_dialog({ question, title = 'Confirm', yes_button_first = true,
has_backdrop = false, height = '250px', width = '350px' }:
{
question: string, title?: string, yes_button_first?: boolean, has_backdrop?: boolean,
height?: string, width?: string
}): MatDialogRef<DialogYesNoComponent> {
const dialog_ref = this.dialog.open(DialogYesNoComponent, {
autoFocus: true,
backdropClass: 'cdk-overlay-transparent-backdrop',
closeOnNavigation: true,
disableClose: false,
hasBackdrop: has_backdrop,
height: height,
width: width,
data: { question: question, title: title, yes_button_first: yes_button_first }
})
return dialog_ref
}
public open_warning_dialog() {
{ warning, title = 'Warning',
has_backdrop = false, height = '250px', width = '350px' }:
{
warning: string, title?: string, has_backdrop?: boolean,
height?: string, width?: string
}): MatDialogRef<DialogWarningComponent> {
const dialog_ref = this.dialog.open(DialogWarningComponent, {
autoFocus: true,
backdropClass: 'cdk-overlay-transparent-backdrop',
closeOnNavigation: true,
disableClose: false,
hasBackdrop: has_backdrop,
height: height,
width: width,
data: { warning: warning, title: title }
})
return dialog_ref
}
}
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
export interface YesNoDialogOptions {
question: string
title: string
yes_button_first: boolean
}
@Component({
selector: 'dialog-yes-no',
templateUrl: './dialog-yes-no.component.html',
styleUrls: ['./dialog-yes-no.component.css']
})
export class DialogYesNoComponent {
constructor(public dialog_ref: MatDialogRef<DialogYesNoComponent>,
@Inject(MAT_DIALOG_DATA) public options: YesNoDialogOptions) { }
}
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
export interface WarningDialogOptions {
warning: string
title: string
}
@Component({
selector: 'dialog-warning',
templateUrl: './dialog-warning.component.html',
styleUrls: ['./dialog-warning.component.css']
})
export class DialogWarningComponent {
constructor(public dialog_ref: MatDialogRef<DialogWarningComponent>,
@Inject(MAT_DIALOG_DATA) public options: WarningDialogOptions) { }
}