问题
I'm getting familiar with how dependency injection works in Angular 2, but I'm trying to figure out if a specific use case is possible.
In short I'd like to have a child component that has a dependency injected like so:
@Component( {
selector: 'child',
template: `
<div class="child">
<span><a href="#" (click)="idService.regenerate()">Regenerate</a></span>
<span>{{idService.id}}</span>
</div>
`
})
export class ChildComponent {
constructor(
protected idService: IdService
)
{}
}
At higher levels of my component tree I am using providers: [IdService]
to inject different instances of the service. This all makes sense and doesn't give me a problem. However, what I'd like to understand is if this is possible without creating a "copy" of the child component with its own providers: [...]
property in the component annotation:
https://plnkr.co/edit/ZMYNIH7lB0Oi6EBSYmfB?p=preview
In that example you'll see the bottom set of components each get a new instance of the IdService
class, but it's because they're really a new component that specifically requests a new instance.
What I'd like to know is if there's a way to achieve this simply with the parent component? Like being able to say "give a new instance each time a child component tries to resolve this specific dependency"?
回答1:
I don't think that it's possible because of the way hierarchical injectors work.
If a component finds a provider within its associated injector, it will use it to get / create the service. If not it will have a look at the parent injector (the injector associated with the parent component) and so on. This is done from the bottom to the top and not the top to the bottom.
If the provider is found in the parent component, all children will use the same instance since the latter is a singleton at this level.
See this question for more details about hierarchical injectors:
- What's the best way to inject one service into another in angular 2 (Beta)?
回答2:
If you want multiple instances (Angular DI creates singletons by default and always returns the same instance) you can use a factory.
(Example code from my answer to https://stackoverflow.com/a/35985703/217408)
@Injectable()
export class User {
firstName:string;
lastName:string;
constructor(user:User, _http:Http){
this.firstName = User.firstName;
this.lastName = User.lastName;
}
getUserFirstName(){
return this.firstName;
}
addUser(){
return this._http.post('/api/user/',this);
}
}
bootstrap(AppComponent, [OtherProviders, HTTP_PROVIDERS,
provide(User, {useFactory:
() => return (http) => new User(http);},
deps: [Http])]);
export class MyComponent {
consturctor(@Inject(User) private userFactory) {
// create new instances by calling the factory
let user = this.userFactory();
}
}
来源:https://stackoverflow.com/questions/36043821/how-to-provide-an-instance-oer-each-child-component