With Angular, the component objects are automatically created and associated with their corresponding elements in the template.
This raises the question then – if you want to refer to a child object from a parent component, how do you do it? There may be multiple child components of the same time in the parent component, so how do you get a reference to a specific one?
As a contrast, when using JSF for example to refer to child component code, the parent managed bean (= component object in Angular) is actually responsible for declaring the managed bean objects for its children. On the page, the child component element will typically have a specific e.g. controller attribute where the managed bean for that child is passed in, e.g. as <child controller=#{controller.child}>… where controller.child refers to the child property of the parent managed bean. In this way, unlike Angular, the object hierarchy is explicitly declared in the code.
In Angular, there are a number of ways to do this, but in the end they all come down to using reference information from a particular template element to direct which object is required.
It is instructive to read the whole section on Angular template syntax in the Angular docs, which includes all the binding techniques.
1/ Passing an element reference in a method call from the template
<ion-auto-complete id="location-search" #locationSearch [dataProvider]="locationsAutoCompleteService"
(itemSelected)="onItemClicked($event, locationSearch)"></ion-auto-complete>
In this case, (itemSelected)="onItemClicked($event, locationSearch)" is passing the element reference #locationSearch as the second argument to onItemClicked. This passes the reference to the component object for <ion-auto-complete>. (Note that in this case the first argument, $event, is the actual location object that was clicked in an autocomplete list).
2/ Using the @ViewChild decorator in the parent class, passing it a child reference used in the template
export class AutoCompleteComponent {
@Input() public dataProvider: any;
@Output() public itemSelected: EventEmitter<any>;
@ViewChild(Searchbar) searchBar: Searchbar;
In this case, the component only contains a single searchbar, so using a class reference is not ambiguous. If there were multiples, the first one would be taken. You can inject references to multiple children via @ViewChildren if there is more than one present – this gives you access to an array of them.
Where you want to use a reference to a specific element, you can use @ViewChild with an element reference, e.g. in 1/ above you would use #locationSearch to inject a referent to the <ion-auto-complete #locationSearch > element as follows:-
@ViewChild(‘#locationSearch’) searchBar: Searchbar;
3/ Another related technique is to make a method call in the template e.g. in an event call, using an element reference to another element in the component. This is detailed here. Note that <child-component #f contains the #f element reference, and the inc() method on the #f element is called from the button click event using <button (click)=”f.inc()”>
@Component({
selector: 'child-component',
inputs: ['bar'],
template: `"{{ bar }}" in child, counter {{ n }}`
})
class ChildComponent{
constructor () {
this.n = 0;
}
inc () {
this.n++;
}
}
@Component({
selector: 'my-app',
template: `
<child-component #f [bar]="bar"></child-component><br>
<button (click)="f.inc()">call child func</button>
<button (click)="bar = 'different'">change parent var</button>
`,
directives: [ChildComponent]
})
class AppComponent {
constructor () {
this.bar = 'parent var';
}
}
bootstrap(AppComponent);
There is a working plunker for the above example here.