javascript – Angular的`@ Host`装饰器没有达到顶峰?
作者:互联网
在我的主要应用程序中,我宣布了一个全球提供商:
providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]
(其中createDependency只是一个返回具有getName()方法的类的函数.)
我也有一个组件:
<my-app-component-3>Hello from 3</my-app-component-3>
代码:
@Component({
selector: 'my-app-component-3',
template: `
<div>Component3:
<ng-content></ng-content>
: <span [innerHTML]="dependency?.getName()"></span>
</div>
`,
})
export class Component3 {
constructor(@Host() @Optional() public dependency: Dependency) {}
}
结果是:
Component3: Hello from 3 :
但我希望结果如下:
Component3: Hello from 3 :AppModule provider
因为基本上app结构是:
<my-app>
<my-app-component-3>
</my-app-component-3>
</my-app>
题:
为什么@Host()与父提供者不匹配?
(即:provider:[{provide:Dependency,useValue:createDependency(‘AppModule provider’)}])
据我所知 – 注射器应该以这种方式寻求依赖:
那为什么不找到呢?
注意
我已经知道,如果我删除@host – 它确实达到了顶峰.我的问题是为什么添加@host – 没有达到顶峰 – 尽管my-component3在我的app下!
解决方法:
查看A curios case of the @Host decorator and Element Injectors in Angular以深入解释@Host装饰器的工作原理以及Element Injectors在这张图片中的位置.
为了使它工作,您应该在父组件中定义依赖项并使用viewProviders:
@Component({
selector: 'my-app',
viewProviders: [{provide: Dependency, useValue: createDependency('AppModule provider')}],
...
export class MyApp {}
以下是metadata.ts内部的评论:
Specifies that an injector should retrieve a dependency from any
injector until reaching the host element of the current component.
所以基本上它表示在解析依赖关系时不使用主机元素注入器和上面的所有注入器.因此,如果您的MyApp组件具有以下模板:
<my-app-component-3></my-app-component-3>
结果组件树看起来像这样:
<my-app>
<my-app-component-3></my-app-component-3>
</my-app>
MyApp组件的注入器和App模块注入器都不用于解析my-app-component-3的依赖关系.
但是,ProviderElementContext._getDependency中有以下有趣的代码执行一项额外的检查:
// 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工作的原因.
所以,这是查找树:
用法
此装饰器主要用于指令以从当前组件视图中的父注入器解析提供程序.即使是unit test is written也只能测试指令.这是一个真实的例子来自表单模块如何使用它的装饰器.
考虑A组件的此模板:
<form name="b">
<input NgModel>
</form>
NgModel指令想要解析form指令提供的提供程序.但是如果提供者不可用,则不需要超出当前组件A.
所以NgModel定义如下:
export class NgModel {
constructor(@Optional() @Host() parent: ControlContainer...)
虽然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 {}
依赖性将得到解决.
标签:javascript,angular,angular-components,angular-decorator 来源: https://codeday.me/bug/20190527/1162896.html