Angular2 - Template reference inside NgSwitch
Asked Answered
I

3

5

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).

Inulin answered 30/7, 2016 at 13:49 Comment(0)
S
5

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.

Shackle answered 31/7, 2016 at 1:33 Comment(1)
thanks for the answer. I find the issue I have in my template. I use ngSwitchCase binding to enum variable as described here #35836484 - if I use this pattern with the enums the view child is undefined even after view is initialized. When I switch to the ng-switch binding to numbers - as I put here in order to simplify the code it works. Do you have any idea why it may happen with enums bindings?Inulin
H
1

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>
Hoxha answered 6/9, 2017 at 11:10 Comment(0)
U
0

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

Uncrown answered 7/7, 2018 at 19:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.