角度`@Host`装饰器没有到达顶部?

2024-05-01

在我的主要app.ts我已宣布成为全球提供商:

providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]

(Where createDependency只是一个返回一个类的函数,该类具有getName() method.)

我还有一个组件:

    <my-app-component-3>Hello from 3</my-app-component-3>

Code :

@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) {}
}

结果是:

组件 3:来自 3 的问候:

但我期望结果是:

组件 3:来自 3 的问候:应用程序模块提供商

因为基本上应用程序结构是:

<my-app>
  <my-app-component-3>
  </my-app-component-3>
</my-app> 

问题:
为什么不@Host()与父提供者匹配 ?

(即:providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}])

据我所知 - 注射器应该寻求Dependency以这种方式 :

那么为什么它找不到呢?

PLUNKER https://plnkr.co/edit/qpsUzaAywtkN6JfbFXMb?p=preview

Notice

我已经知道如果我删除@host- 它确实达到了顶峰。我的问题是为什么添加 @host - 没有到达顶部 - 尽管事实上my-component3在下面my-app !!


查看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将会得到解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

角度`@Host`装饰器没有到达顶部? 的相关文章

随机推荐