查看Angular 中 @Host 装饰器和元素注入器的一个奇怪案例 https://blog.angularindepth.com/a-curios-case-of-the-host-decorator-and-element-injectors-in-angular-582562abcf0a深入解释 @Host 装饰器如何工作以及元素注入器在这张图中的作用。
为了让它工作,你应该在在父组件中并使用视图提供者:
@Component({
selector: 'my-app',
viewProviders: [{provide: Dependency, useValue: createDependency('AppModule provider')}],
...
export class MyApp {}
这是里面的评论元数据.ts https://github.com/angular/angular/blob/cbd93fe0d0624ce5920f966027df534fd9b50b85/packages/core/src/di/metadata.ts#L252 say:
指定注入器应该从任何
注射器until到达当前组件的宿主元素。
所以基本上它说的是一个主机元件注入器和上面的所有注入器are not解决依赖关系时使用。所以如果你的MyApp
组件具有以下模板:
<my-app-component-3></my-app-component-3>
生成的组件树如下所示:
<my-app>
<my-app-component-3></my-app-component-3>
</my-app>
neither MyApp
组件的注入器或应用程序模块注入器are用于解决依赖关系my-app-component-3
.
然而,有以下有趣的代码ProviderElementContext._getDependency https://github.com/angular/angular/blob/9dc310eb50f022b25184e84a3a9abc016e4a2451/packages/compiler/src/provider_analyzer.ts#L290执行一项附加检查:
// check @Host restriction
if (!result) {
if (!dep.isHost || this.viewContext.component.isHost ||
this.viewContext.component.type.reference === tokenReference(dep.token !) ||
// this line
this.viewContext.viewProviders.get(tokenReference(dep.token !)) != null) { <------
result = dep;
} else {
result = dep.isOptional ? result = {isValue: true, value: null} : null;
}
}
它基本上检查提供者是否在中定义viewProviders
并解决(如果找到)。这就是为什么viewProviders
work.
所以,这是查找树:
Usage
该装饰器主要用于从当前组件视图中的父注入器解析提供程序的指令。即便是单元测试已编写 https://github.com/angular/angular/blob/master/packages/examples/core/di/ts/metadata_spec.ts#L135仅用于测试指令。这是一个真实的例子forms
模块如何使用它的装饰器。
考虑此模板A
成分:
<form name="b">
<input NgModel>
</form>
NgModel
指令想要解析由form
指示。但如果提供者不可用,则无需超出当前组件的范围A
.
So NgModel
定义如下:
export class NgModel {
constructor(@Optional() @Host() parent: ControlContainer...)
While form
指令定义如下:
@Directive({
selector: '[formGroup]',
providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
...
})
export class NgForm
此外,指令可以注入由其托管组件定义的依赖项(如果它们是用以下命令定义的)viewProviders
。例如,如果MyApp
组件定义如下:
@Component({
selector: 'my-app',
viewProviders: [Dependency],
template: `<div provider-dir></div>`
})
export class AppComponent {}
the Dependency
将会得到解决。