通过 DI 装饰器优雅地限制指令在特定指令上使用
Gracefully restrict a directive to be used on a specific directive via DI decorators
在我的应用程序中,我引入了一个映射器指令,负责从 class 填充表单值。旨在用于:
<form [formGroup]="form" [myItemMapper]="item$ | async">
不打算在任何其他元素上,例如表单数组或表单控件。
为了实现这个意图,我将选择器限制为 [formGroup][myItemMapper]
,这是可行的,即。如果你把这个指令放在任何其他元素上,你会得到一个很大的 Webpack 编译覆盖层,上面有错误说
`NG8002: Can't bind to 'myItemMapper' since it isn't a known property of '<whatever>'.
目标达成。
但我想知道为什么以下代码不起作用:
constructor(
@Self() fg: FormGroupDirective,
) {
if(!fg){
console.error("'myItemMapper' can only be used on a FormGroup directive.")
}
}
- 而不是一个很好的信息
console.error
,我得到了一个令人讨厌的“找不到 formGroupDirective 的提供者”运行时错误,没有任何解释。对于消费者来说,这是一种误导性体验,就好像他们根本没有进口 ReactiveFormsModule
。
也尝试了 @Host()
- 它基本上不关心指令在哪个元素上,当它被放置在 formControlName
上时它也能够找到 formGroup
-还有一点不明白。
那么 - 第一个选项是我能为指令的消费者提供的最佳选择吗?
添加 [formGroup][myItemMapper]
作为指令的选择器时,您是在告诉编译器 MyItemMapperDirective
必须与 FormGroupDirective
一起使用。这可以在编译时强制执行。
通过添加 FormGroupDirective
作为构造函数参数,您要求依赖注入容器将其作为依赖项找到。由于依赖项会在 运行 时间受到其他组件的影响,因此所需的依赖项是否存在只能在 运行 时间确定,因此您会看到错误消息。
是的,第一个选项是您最好的选择。
But I was wondering why the following code didn't work:
instead of a nice informative console.error, I got a nasty "No provider for formGroupDirective found" runtime error with no explanation. For a consumer it is a misleading experience as if they didn't import ReactiveFormsModule at all.
当无法解析依赖关系时,Angular 将抛出错误“找不到 {token} 的提供程序”。这是预期的行为。
如果您想打印 console.error
消息而不是抛出错误,您还应该使用 @Optional()
装饰器作为:
constructor(
@Self() @Optional() fg: FormGroupDirective,
) {
if(!fg){
console.error("'myItemMapper' can only be used on a FormGroup directive.")
}
}
来自docs
@Optional() allows Angular to consider a service you inject to be optional. This way, if it can't be resolved at runtime, Angular resolves the service as null, rather than throwing an error.
现在进入下一个问题:
Tried @Host() too - it basically didn't care which element the directive was on, it was able to find formGroup also when it was placed on a formControlName- which is also something I don't understand.
当使用@Host()
时,Angular会从当前Injector开始依赖解析,并会在Injector层级中继续搜索,直到到达宿主元素 当前组件。
假设您的 SomeComponent
:
有以下模板
<form [formGroup]="form">
<label for="firstName">First Name</label>
<input id="firstName" type="text" formControlName="firstName" yourDirective />
</form>
然后在指令构造函数中使用 @Host(),Angular 将尝试按如下方式解析依赖关系:
yourDirective
的提供程序数组,后跟 FormControlName
指令的提供程序数组
- 供应商数组
FormGroupDirective
- viewProviders 数组
SomeComponent
在我的应用程序中,我引入了一个映射器指令,负责从 class 填充表单值。旨在用于:
<form [formGroup]="form" [myItemMapper]="item$ | async">
不打算在任何其他元素上,例如表单数组或表单控件。
为了实现这个意图,我将选择器限制为 [formGroup][myItemMapper]
,这是可行的,即。如果你把这个指令放在任何其他元素上,你会得到一个很大的 Webpack 编译覆盖层,上面有错误说
`NG8002: Can't bind to 'myItemMapper' since it isn't a known property of '<whatever>'.
目标达成。
但我想知道为什么以下代码不起作用:
constructor(
@Self() fg: FormGroupDirective,
) {
if(!fg){
console.error("'myItemMapper' can only be used on a FormGroup directive.")
}
}
- 而不是一个很好的信息
console.error
,我得到了一个令人讨厌的“找不到 formGroupDirective 的提供者”运行时错误,没有任何解释。对于消费者来说,这是一种误导性体验,就好像他们根本没有进口ReactiveFormsModule
。
也尝试了 @Host()
- 它基本上不关心指令在哪个元素上,当它被放置在 formControlName
上时它也能够找到 formGroup
-还有一点不明白。
那么 - 第一个选项是我能为指令的消费者提供的最佳选择吗?
添加 [formGroup][myItemMapper]
作为指令的选择器时,您是在告诉编译器 MyItemMapperDirective
必须与 FormGroupDirective
一起使用。这可以在编译时强制执行。
通过添加 FormGroupDirective
作为构造函数参数,您要求依赖注入容器将其作为依赖项找到。由于依赖项会在 运行 时间受到其他组件的影响,因此所需的依赖项是否存在只能在 运行 时间确定,因此您会看到错误消息。
是的,第一个选项是您最好的选择。
But I was wondering why the following code didn't work:
instead of a nice informative console.error, I got a nasty "No provider for formGroupDirective found" runtime error with no explanation. For a consumer it is a misleading experience as if they didn't import ReactiveFormsModule at all.
当无法解析依赖关系时,Angular 将抛出错误“找不到 {token} 的提供程序”。这是预期的行为。
如果您想打印 console.error
消息而不是抛出错误,您还应该使用 @Optional()
装饰器作为:
constructor(
@Self() @Optional() fg: FormGroupDirective,
) {
if(!fg){
console.error("'myItemMapper' can only be used on a FormGroup directive.")
}
}
来自docs
@Optional() allows Angular to consider a service you inject to be optional. This way, if it can't be resolved at runtime, Angular resolves the service as null, rather than throwing an error.
现在进入下一个问题:
Tried @Host() too - it basically didn't care which element the directive was on, it was able to find formGroup also when it was placed on a formControlName- which is also something I don't understand.
当使用@Host()
时,Angular会从当前Injector开始依赖解析,并会在Injector层级中继续搜索,直到到达宿主元素 当前组件。
假设您的 SomeComponent
:
<form [formGroup]="form">
<label for="firstName">First Name</label>
<input id="firstName" type="text" formControlName="firstName" yourDirective />
</form>
然后在指令构造函数中使用 @Host(),Angular 将尝试按如下方式解析依赖关系:
yourDirective
的提供程序数组,后跟FormControlName
指令的提供程序数组- 供应商数组
FormGroupDirective
- viewProviders 数组
SomeComponent