5

I have parent component, there is a ng-template section. Under this ng-template section there is a Child Component. Now I would like to access this child component with ViewChild decorator. After getting with ViewChild I want to execute a function of that child component. But it’s not working. The code is below:

<ng-template #mymodal let-modal>
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Bootstrap Modal</h4>
    <button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <app-expense-head #child></app-expense-head>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('Save click')">Ok</button>
    <button type="button" class="btn btn-outline-dark" (click)="onClickCancel()">Cancel</button>
  </div>
</ng-template>

TS file code

@ViewChild(ExpenseHeadComponent, { static: false }) childExpenseHead: ExpenseHeadComponent;

onClickCancel() {
    this.childExpenseHead.myAlert();    
  }
mnu-nasir
  • 1,642
  • 5
  • 30
  • 62

3 Answers3

1

Try accessing child value on ngAfterViewInit() { } life cycle hook.

Jobelle
  • 2,717
  • 1
  • 15
  • 26
1

You already added template reference in child using #child. So in template, you can access the public methods in child using this reference like below

 (click) ="child.myAlert()"
Jobelle
  • 2,717
  • 1
  • 15
  • 26
  • 1
    Yes, it's working. but is it not possible to catch the child with ViewChild decorator and call onClickCancel function when button click? – mnu-nasir Jan 09 '21 at 16:58
1

It can work from the class code. See below example that is similar in structure to your code and notice the use of ngAfterViewInit and ViewChild:

See it working here.

HTML (parent component)

<ng-template #myTemplate>
  <hello name="{{ name }}"></hello>
</ng-template>
<button (click)="clickChild()">Call Child</button>

TS (parent component)

import { AfterViewInit, Component, EmbeddedViewRef, OnInit,  TemplateRef, VERSION, ViewChild, ViewContainerRef } from '@angular/core';
import { HelloComponent } from './hello.component';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit, AfterViewInit  {
  @ViewChild(HelloComponent, { static: false }) child: HelloComponent;
  @ViewChild('myTemplate', { static: false, read: TemplateRef }) myTemplate: TemplateRef<any>;
  name = 'Angular ' + VERSION.major;

  constructor(private viewContainerRef: ViewContainerRef) {}
  
  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    const embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.myTemplate);

    embeddedViewRef.detectChanges();
  }

  clickChild(): void {
    this.child.myAlert();
  }
}

HTML and ts (child component)

import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string;

  myAlert(): void {
    console.log('in hello component');
    alert('alert child');
  }
}
Benny Halperin
  • 1,872
  • 3
  • 13
  • 18
  • The child component is shown in the below which I don't want. Because the child component will only show when the modal is show. – mnu-nasir Jan 10 '21 at 05:45
  • @mnu-nasir do you want to call `this.childExpenseHead.myAlert();` from the parent component or the modal component? Anyway it would be helpful if you could post your code on StackBlitz - at least something minimal that reproduces the problem. – Benny Halperin Jan 10 '21 at 07:02