I have a NgSwitch template. In the NgSwitch I want to get a template reference to the initialized template. Something like this:
<div class="container" [ngSwitch]="model.type">
<first-component #ref *ngSwitchCase="0"></first-component>
<second-component #ref *ngSwitchCase="1"></second-component>
<third-component #ref *ngSwitchCase="2"></third-component>
</div>
When clicking on a button in the component I want to call to the initialized component (first/second/third) to a method (which defined on an interface that all these 3 component implement). The problem is the ViewChild is undefined. If I move #ref to the container div, like this:
<div class="container" #ref [ngSwitch]="model.type">
<first-component *ngSwitchCase="0"></first-component>
<second-component *ngSwitchCase="1"></second-component>
<third-component *ngSwitchCase="2"></third-component>
</div>
The ViewChild (template reference) is initialized but then I can call the method of the component.
How can I use both NgSwitch directive and template reference variable?
Or on the other hand, how can I call the initialized component from its parent (in a case I move the #ref to the container div).
It works if you use a template reference variable at the ngSwitchCase
, this way:
<div class="container" [ngSwitch]="model.type">
<first-component #ref *ngSwitchCase="0"></first-component>
<second-component #ref *ngSwitchCase="1"></second-component>
<third-component #ref *ngSwitchCase="2"></third-component>
</div>
Notice that, if you have:
export class SomeComponent {
@ViewChild('ref') ref;
...
Then ref
is not yet set at when the constructor is called. Not even on init. Only after view init.
This way, with the following component:
export class AppComponent implements OnInit, AfterViewInit {
model = {type: 0};
@ViewChild('ref') ref;
constructor() {
console.log('constructor:', this.ref);
}
ngOnInit() {
console.log('ngOnInit:', this.ref);
}
ngAfterViewInit() {
console.log('AfterViewInit:', this.ref);
}
}
The output is:
constructor: undefined
ngOnInit: undefined
AfterViewInit: FirstComponent {...}
See demo plunker here.
Template reference variable should not work with structural directive. Here is explained a reason : Thomas Hilzendegen's blog
My solution is to make a template reference variable for a container tag where [ngSwitch] is used and then access to it's child using it's children property. For example
<div [ngSwitch]="..." [class.error] = "(elem.children.item(0).className.indexOf('someClass') !== -1" #elem>
...
</div>
Also you can use forwardRef
without any template references like below:
@Component({
...
selector: 'first-component',
providers: [{
provide: BaseEnumeratedComponent,
useExisting: forwardRef(() => FirstComponent)
}]
})
And access to list of components which use switch-case using ngAfterViewInit()
in parent component. Or if you want to access certain one use provide: FirstComponent