javascript - Angular 的 `@Host` 装饰器没有到达顶部?

标签 javascript angular angular-components angular-decorator

在我的主要 app.ts 中,我声明了一个全局提供者:

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

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

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

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

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

据我所知 - 注入(inject)器应该以这种方式寻找 Dependency :

enter image description here

那么为什么它找不到呢?

PLUNKER

注意事项

我已经知道,如果我删除 @host - 它会到达顶部。我的问题是为什么添加 @host - 没有到达顶部 - 尽管 my-component3my-app 下!!

最佳答案

查看 A curios case of the @Host decorator and Element Injectors in Angular深入解释@Host 装饰器的工作原理以及元素注入(inject)器在这幅图中的作用。

为了使其正常工作,您应该在父组件 中定义依赖项并使用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.

所以基本上它表示在解析依赖项时,宿主元素注入(inject)器和上面的所有注入(inject)器都不会使用。因此,如果您的 MyApp 组件具有以下模板:

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

生成的组件树如下所示:

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

MyApp 组件的注入(inject)器和 App 模块注入(inject)器都用于解决 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 起作用的原因。

所以,这是查找树:

enter image description here

用法

这个装饰器主要用于在当前组件 View 中解析来自父注入(inject)器的提供者的指令。即使是 unit test is written仅用于测试指令。这是 forms 模块中如何使用装饰器的真实示例。

考虑 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

此外,指令可以注入(inject)由其托管组件定义的依赖项,如果它们是使用 viewProviders 定义的。例如,如果 MyApp 组件定义如下:

@Component({
    selector: 'my-app',
    viewProviders: [Dependency],
    template: `<div provider-dir></div>`
})
export class AppComponent {}

依赖将被解析。

关于javascript - Angular 的 `@Host` 装饰器没有到达顶部?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47602697/

相关文章:

javascript - 继承:如何在重写的方法中模拟 super.method

javascript - 使用滑出菜单推送 html 内容

javascript - 如何正确使用 Nan::HandleScope?

javascript - 如何将服务中的数据分配给 JSON?

Angular2 RC5 没有 ViewResolver

angular - 在 Angular Testing 中将表单控件设置为脏

javascript - 下拉 Javascript 菜单重叠

angular - check_box_outline 图标占用额外空间

javascript - 在 Angular 6 component.html 中使用 script 标签

angular - AngularDart组件下拉列表选择selectionChange事件