Tom*_*Law 10 dialog circular-dependency angular
我正在开发一个 Angular 7 应用程序,它允许管理实体,例如汽车和学生。
应用程序组件可以用以下树来描述:
在CreateCar对话框中创建 Car 时,用户应该能够使用CreateStudent对话框创建并指定一个新学生作为 Car 的所有者。
同样,在CreateStudent对话框中创建 Student 时,用户应该能够使用CreateCar对话框创建和分配一辆新车作为 Student 的属性。
编译时,Angular 显示:“检测到循环依赖项中的警告”,我知道这应该发生。
我试过寻找模式来解决这个问题,例如共享服务,但似乎没有人工作。
编辑:
两个对话框的构造函数的相关部分:
constructor(
private readonly matDialog: MatDialog
) {
}
Run Code Online (Sandbox Code Playgroud)
在 CreateStudent 对话框中,打开 CreateCar 对话框的方法:
createCar(): void {
this.matDialog
.open(CreateCarDialogComponent)
.afterClosed().subscribe((car: Car) => {
// Do something with car
});
}
Run Code Online (Sandbox Code Playgroud)
在 CreateCar 对话框中,打开 CreateStudent 对话框的方法:
createStudent(): void {
this.matDialog
.open(CreateStudentDialogComponent)
.afterClosed().subscribe((student: Student) => {
// Do something with student
});
}
Run Code Online (Sandbox Code Playgroud)
关于解决这个问题的任何建议?
谢谢
编辑2:
演示在这里 https://stackblitz.com/edit/angular-bbfs8k
(Stackblitz 似乎没有显示编译警告)
Rea*_*lar 13
在MatDialog不需要直接引用组件声明。您只需要传递一个ComponentType<any>参数即可打开一个对话框。所以我们可以通过使用 Angular 依赖注入器来解决循环依赖(由 TypeScript 触发)。
创建一个命名的文件create-card-token.ts并定义一个注入令牌。
export const CREATE_CAR_TOKEN: InjectionToken<ComponentType<any>> =
new InjectionToken<ComponentType<any>>('CREATE_CAR_TOKEN');
Run Code Online (Sandbox Code Playgroud)
在您的模块中,将上述令牌的值定义为提供者。您可以在此处定义将用于MatDialog.
@NgModule({
....
providers: [
{provide: CREATE_CAR_TOKEN, useValue: CreateCarComponent}
]
}) export class MyModule {}
Run Code Online (Sandbox Code Playgroud)
在 中,CarComponent您现在可以注入此令牌并使用它打开对话框。
@Component({...})
export class CarComponent {
public constructor(@Inject(CREATE_CAR_TOKEN) private component: ComponentType<any>,
private matDialog: MatDialog) {}
public createCar() {
this.matDialog
.open(this.component)
.afterClosed().subscribe((car: Car) => {
// Do something with car
});
}
}
Run Code Online (Sandbox Code Playgroud)
这将解决循环依赖,因为CarComponent永远不需要知道CreateCarComponent. 相反,它只知道 aComponentType<any>已被注入,并且MyModule定义了将使用哪个组件。
还有一个问题。上面的示例any用作将要创建的组件类型。如果需要访问对话框实例,并直接从 调用方法CarComponent,则可以声明接口类型。关键是将界面保存在一个单独的文件中。如果您从CreateCarComponent文件中导出接口,您将回到具有循环依赖关系。
例如;
export interface CreateCarInterface {
doStuff();
}
Run Code Online (Sandbox Code Playgroud)
然后更新令牌以使用该接口。
export const CREATE_CAR_TOKEN: InjectionToken<ComponentType<CreateCarInterface>> =
new InjectionToken<ComponentType<CreateCarInterface>>('CREATE_CAR_TOKEN');
Run Code Online (Sandbox Code Playgroud)
然后你可以doStuff()像这样从汽车组件调用:
@Component({...})
export class CarComponent {
public constructor(@Inject(CREATE_CAR_TOKEN) private component: ComponentType<CreateCarInterface>,
private matDialog: MatDialog) {}
public createCar() {
const ref = this.matDialog.open(this.component);
ref.componentInstance.doStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以在CreateCarComponent.
@Component({..})
export class CreateCarComponent implements CreateCarInterface {
public doStuff() {
console.log("stuff");
}
}
Run Code Online (Sandbox Code Playgroud)
此类循环引用经常发生MatDialog在 CDK 门户上,因为我们经常需要让一个服务打开对话框,然后该对话框出于其他原因需要使用相同的服务。我已经发生过很多次了。
建议: