admin管理员组文章数量:1315237
In my main app.ts
I've declared a global provider :
providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]
(Where createDependency
is just a function that returns a class which has a getName()
method.)
I also have a ponents :
<my-app-ponent-3>Hello from 3</my-app-ponent-3>
Code :
@Component({
selector: 'my-app-ponent-3',
template: `
<div>Component3:
<ng-content></ng-content>
: <span [innerHTML]="dependency?.getName()"></span>
</div>
`,
})
export class Component3 {
constructor(@Host() @Optional() public dependency: Dependency) {}
}
The result is:
Component3: Hello from 3 :
But I expect the result to be :
Component3: Hello from 3 :AppModule provider
Because basically the app structure is :
<my-app>
<my-app-ponent-3>
</my-app-ponent-3>
</my-app>
Question:
Why doesn't @Host()
match the parent provider ?
(which is : providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]
)
To my knowledge - the injector should seek for a Dependency
in this manner :
So why doesn't it find it ?
PLUNKER
Notice
I already know that if I remove @host
- it does reach the top. My question is why adding @host - is not reaching the top - despite the fact thatmy-ponent3
is under my-app
!!
In my main app.ts
I've declared a global provider :
providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]
(Where createDependency
is just a function that returns a class which has a getName()
method.)
I also have a ponents :
<my-app-ponent-3>Hello from 3</my-app-ponent-3>
Code :
@Component({
selector: 'my-app-ponent-3',
template: `
<div>Component3:
<ng-content></ng-content>
: <span [innerHTML]="dependency?.getName()"></span>
</div>
`,
})
export class Component3 {
constructor(@Host() @Optional() public dependency: Dependency) {}
}
The result is:
Component3: Hello from 3 :
But I expect the result to be :
Component3: Hello from 3 :AppModule provider
Because basically the app structure is :
<my-app>
<my-app-ponent-3>
</my-app-ponent-3>
</my-app>
Question:
Why doesn't @Host()
match the parent provider ?
(which is : providers: [{provide: Dependency, useValue: createDependency('AppModule provider')}]
)
To my knowledge - the injector should seek for a Dependency
in this manner :
So why doesn't it find it ?
PLUNKER
Notice
I already know that if I remove @host
- it does reach the top. My question is why adding @host - is not reaching the top - despite the fact thatmy-ponent3
is under my-app
!!
4 Answers
Reset to default 9 +50Check out A curios case of the @Host decorator and Element Injectors in Angular for in-depth explanation of how @Host decorator works and where Element Injectors e into this picture.
In order for it to work you should define dependencies in the in the parent ponent and using viewProviders:
@Component({
selector: 'my-app',
viewProviders: [{provide: Dependency, useValue: createDependency('AppModule provider')}],
...
export class MyApp {}
Here is what the ments inside metadata.ts say:
Specifies that an injector should retrieve a dependency from any injector until reaching the host element of the current ponent.
So basically it says that a host element injector and all injectors above are not used when resolving a dependency. So if your MyApp
ponent has the following template:
<my-app-ponent-3></my-app-ponent-3>
and the resulting ponents tree look like this:
<my-app>
<my-app-ponent-3></my-app-ponent-3>
</my-app>
neither MyApp
ponent's injector nor App module injectors are used to resolve dependency for the my-app-ponent-3
.
However, there's the following interesting code in the ProviderElementContext._getDependency that performs one additional check:
// check @Host restriction
if (!result) {
if (!dep.isHost || this.viewContext.ponent.isHost ||
this.viewContext.ponent.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;
}
}
which basically checks if the provider is defined in the viewProviders
and resolves it if found. That's why viewProviders
work.
So, here is the lookup tree:
Usage
This decorator is mostly used for directives to resolve providers from the parent injector within the current ponent view. Even the unit test is written only to test directives. Here is a real example from the forms
module how it's decorator is used.
Consider this template for the A
ponent:
<form name="b">
<input NgModel>
</form>
NgModel
directive wants to resolve a provider supplied by the form
directive. But if the provider is not available, there's no need to go outside of a current ponent A
.
So NgModel
is defined like this:
export class NgModel {
constructor(@Optional() @Host() parent: ControlContainer...)
While form
directive is defined like this:
@Directive({
selector: '[formGroup]',
providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
...
})
export class NgForm
Also, a directive can inject dependencies defined by its hosting ponent if they are defined with viewProviders
. For example, if MyApp
ponent is defined like this:
@Component({
selector: 'my-app',
viewProviders: [Dependency],
template: `<div provider-dir></div>`
})
export class AppComponent {}
the Dependency
will be resolved.
I wonder if the @Optional() is injecting null. I believe that one might be the culprit.
Edit
So from your plunker I can’t seem to find an actual host for the ponent 3. Something like
<parent-ponent>
<ponent-3><ponent-3/>
<parent-ponent/>
On my understanding here it seems what it’s looking for.
just remove @Host() decorator from your Component 3 constructor:
Component({
selector: 'my-app-ponent-3',
template: `
<div>Component3:
<ng-content></ng-content>
: <span [innerHTML]="dependency?.getName()"></span></div>
`,
})
export class Component3 {
constructor(@Optional() public dependency: Dependency) {}
}
Angular will take the provider from the AppModule.
straight from Angular's docs on dependency injection and the Host decorator: https://angular.io/guide/dependency-injection-in-action#qualify-dependency-lookup-with-optional-and-host
The @Host decorator stops the upward search at the host ponent.
The host ponent is typically the ponent requesting the dependency.
with the @Host decorator, you're telling it to only check the host ponent for a provider, and you're making it optional, so it's just seeing there's no provider and quitting.
In practice, the use case for the Host decorator is extremely narrow, and really only ever makes sense if you're projecting content.
本文标签: javascriptAngular39s Host decorator not reaching the topStack Overflow
版权声明:本文标题:javascript - Angular's `@Host` decorator not reaching the top? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741974776a2408053.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论