46

I'd like to know the best way to do this, and if there are different ways. I'm trying to call a function in a child component from its parent component. So if I have:

<parent>
    <child></child>
</parent>

...and child has functions called show() or hide(), how can I call either of those from parent?

BBaysinger
  • 6,614
  • 13
  • 63
  • 132

3 Answers3

95

Inside of your template, using template variables/references:

<parent (click)="yourChild.hide()">
    <child #yourChild></child>
</parent>

live-demo: https://stackblitz.com/edit/angular-so-3?file=src%2Fapp%2Fapp.component.html

OR

Inside of your component:

import { ..., ViewChild, ... } from '@angular/core';

// ...

export class ParentComponent {
   @ViewChild('yourChild' /* #name or Type*/, {static: false}) child;

   ngAfterViewInit() {
      console.log('only after THIS EVENT "child" is usable!!');
      this.child.hide();
   }
}

Inside of your component (option2):

import { ..., ViewChild, ... } from '@angular/core';
import { ..., ChildComponent, ... } from '....';

// ...

export class ParentComponent {
   @ViewChild(ChildComponent /* #name or Type*/, {static: false}) child;

   ngAfterViewInit() {
      console.log('only after THIS EVENT "child" is usable!!');
      this.child.hide();
   }
}

See the official docs: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-view-child

slaesh
  • 16,659
  • 6
  • 50
  • 52
  • 2
    Excellent. So when passing a class name to @ViewChild, it automatically picks up any ChildComponent instanced by the template? – BBaysinger Jan 31 '17 at 19:43
  • 2
    Exactly, I am not sure if its the first or last if multiple childs. But you could use `ViewChildren` for multiple childs! Same way using name or class. – slaesh Jan 31 '17 at 19:44
  • 4
    Added a demo plunker. If there are multiple children of the same class, `ViewChild` will pick up the first found! ;) – slaesh Jan 31 '17 at 19:53
  • Is vise versa of this scenario possible? lets say we have functions in parent component and calling it from child component – amansoni211 Feb 09 '17 at 06:33
  • @amansoni211 you could use a shared service for that functions, or you have to use `@Input` on your child and pass the parent to it.. see this plunker to demonstrate it: https://plnkr.co/edit/RxUKg93ZA3VkYB7eKGaK?p=preview :) – slaesh Feb 09 '17 at 06:53
  • 1
    Really good answer, clear, concise, to the point, no faffing! – danday74 May 27 '18 at 01:42
4

For calling a function of a child, you'll need @ViewChild. However, for showing/hiding a component, you are better off solving this within the template:

<parent>
    <button (click)="showChild=!showChild">Toggle child</button>
    <child *ngIf="showChild"></child>
</parent>

No need for declaring a custom function hide().

phil294
  • 10,038
  • 8
  • 65
  • 98
4

Well the other answers are just correct, but I think some times that function is supposed to be called with the flow of the data the angular way from parent to child, so what you actually need is to run a function every time a variable has changed in the parent component. see below:

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  name = "Angular";
  variable = "yes!";
  toggle() {
    this.variable = this.variable === "yes!" ? "hell no!" : "yes!";
  }
}

app tempalte:

<button (click)="toggle()">Toggle</button>

Parent says: {{variable}}    

<p>
 <app-child [childVar]="variable"></app-child>
</p>

child component:

export class ChildComponent implements OnInit {
  _childVar: string; // if you need to record the value and access later in child component
  counter = 0;

  @Input()
  set childVar(value: string) {
    this._childVar = value;
    this.childFunction(); // the answer is here
  }

  childFunction() {
    this.counter++;
    console.log("called child function");
  }

}

test here https://stackblitz.com/edit/angular-1rywfc

azerafati
  • 18,215
  • 7
  • 67
  • 72