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

0

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for the answer. I find the issue I have in my template. I use ngSwitchCase binding to enum variable as described here stackoverflow.com/questions/35835984/… - 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?
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>

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.