Reputation: 8670
I'm unable to instantiate my application when I have the component which is nested under the root component providing
a component which it uses in it's constructor.
import {Component, Injectable} from 'angular2/core';
@Component()
export class GrandChild(){
constructor () {
this.hello = "hey!"
}
}
@Component({
providers: [GrandChild]
})
@Injectable()
export class Child {
constructor(public grandchild: GrandChild) {
this.grandchild = grandchild;
}
}
@Component({
providers: [Child],
template: `Everything rendered fine!`,
selector: 'app'
})
export class App {
kid: Child;
constructor(public child: Child) {
this.kid = child;
}
}
EXCEPTION: No provider for GrandChild! (App -> Child -> GrandChild)
I'm wondering why this behavior is illegal. Let's say I wanted to use the GrandChild
class in my Child
class and simply reference the Child
class in my App
class. This seems to be impossible.
What is the correct way to create the provide
hierarchy?
Thanks a bunch.
PLNKR: http://plnkr.co/edit/5Z0QMAEyZNUAotZ6r7Yi?p=preview
Upvotes: 0
Views: 1560
Reputation: 202138
You can inject directly the parent component into a component without specifying it into component providers. To do that you need to use component into other ones and set it into the directives
attribute:
@Component({
selector: 'child',
template: `
<div></div>
`
})
export class Child {
constructor(@Inject(forwardRef(() => App)) parent: App) {
}
}
@Component({
directives: [Child],
template: `
Everything rendered fine!
<child></child>
`,
selector: 'app'
})
export class App {
constructor() {
}
}
What is a bit strange in your sample is that you didn't define selector
and template
properties for components Child
and GrandChild
. Are they really components?
In your sample, you made things in the wrong way. If you want to get instances of child component from a parent component, you need to leverage the @ViewChild
decorator to reference the child component from the parent one by injection:
import { Component, ViewChild } from 'angular2/core';
(...)
@Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<child></child>
<button (click)="submit()">Submit</button>
`,
directives:[App]
})
export class AppComponent {
@ViewChild(SearchBar) searchBar:SearchBar;
(...)
someOtherMethod() {
this.searchBar.someMethod();
}
}
Here is the updated plunkr: http://plnkr.co/edit/mrVK2j3hJQ04n8vlXLXt?p=preview.
You can notice that the @Query
parameter decorator could also be used:
export class AppComponent {
constructor(@Query(SearchBar) children:QueryList<SearchBar>) {
this.childcmp = children.first();
}
(...)
}
You can notice that you don't need the @Injectable
decorator when you have the @Component
one...
Upvotes: 1
Reputation: 96891
You can fix it by adding GrandChild
to App
's providers.
However, I don't understand why you were annotating Child
and GrandChild
as @Component
when you're using them as services. I guess this is what you actually wanted to do.
@Injectable()
export class GrandChild(){
constructor () {
this.hello = "hey!"
}
}
@Injectable()
export class Child {
tire: string;
constructor(public grandchild: GrandChild) {
this.grandchild = grandchild;
}
}
@Component({
providers: [Child, GrandChild],
template: `Everything rendered fine!`,
selector: 'app'
})
export class App {
thread: Thread;
selected: boolean = false;
kid: Child;
constructor(public child: Child) {
this.kid = child;
}
}
See updated plnkr demo.
Upvotes: 1