Call child component method from parent class - Angular
Solution 1
You can do this by using @ViewChild
for more info check this link
With type selector
child component
@Component({
selector: 'child-cmp',
template: '<p>child</p>'
})
class ChildCmp {
doSomething() {}
}
parent component
@Component({
selector: 'some-cmp',
template: '<child-cmp></child-cmp>',
directives: [ChildCmp]
})
class SomeCmp {
@ViewChild(ChildCmp) child:ChildCmp;
ngAfterViewInit() {
// child is set
this.child.doSomething();
}
}
With string selector
child component
@Component({
selector: 'child-cmp',
template: '<p>child</p>'
})
class ChildCmp {
doSomething() {}
}
parent component
@Component({
selector: 'some-cmp',
template: '<child-cmp #child></child-cmp>',
directives: [ChildCmp]
})
class SomeCmp {
@ViewChild('child') child:ChildCmp;
ngAfterViewInit() {
// child is set
this.child.doSomething();
}
}
Solution 2
I think most easy way is using Subject. In below example code, the child will be notified each time 'tellChild()' is called.
Parent.component.ts
import {Subject} from 'rxjs/Subject';
...
export class ParentComp {
changingValue: Subject<boolean> = new Subject();
tellChild() {
this.changingValue.next(true);
}
}
Parent.component.html
<my-comp [changing]="changingValue"></my-comp>
Child.component.ts
...
export class ChildComp implements OnInit{
@Input() changing: Subject<boolean>;
ngOnInit(){
this.changing.subscribe(v => {
console.log('value is changing', v);
});
}
}
Working sample on Stackblitz
Solution 3
This Worked for me ! For Angular 2 , Call child component method in parent component
Parent.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from '../child/child';
@Component({
selector: 'parent-app',
template: `<child-cmp></child-cmp>`
})
export class parentComponent implements OnInit{
@ViewChild(ChildComponent ) child: ChildComponent ;
ngOnInit() {
this.child.ChildTestCmp(); }
}
Child.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'child-cmp',
template: `<h2> Show Child Component</h2><br/><p> {{test }}</p> `
})
export class ChildComponent {
test: string;
ChildTestCmp()
{
this.test = "I am child component!";
}
}
Solution 4
Angular – Call Child Component’s Method in Parent Component’s Template
You have ParentComponent and ChildComponent that looks like this.
parent.component.html
parent.component.ts
import {Component} from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() {
}
}
child.component.html
<p>
This is child
</p>
child.component.ts
import {Component} from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
constructor() {
}
doSomething() {
console.log('do something');
}
}
When serve, it looks like this:
When user focus on ParentComponent’s input element, you want to call ChildComponent’s doSomething() method.
Simply do this:
- Give app-child selector in parent.component.html a DOM variable name (prefix with # – hashtag), in this case we call it appChild.
- Assign expression value (of the method you want to call) to input element’s focus event.
The result:
Solution 5
user6779899's answer is neat and more generic However, based on the request by Imad El Hitti, a light weight solution is proposed here. This can be used when a child component is tightly connected to one parent only.
Parent.component.ts
export class Notifier {
valueChanged: (data: number) => void = (d: number) => { };
}
export class Parent {
notifyObj = new Notifier();
tellChild(newValue: number) {
this.notifyObj.valueChanged(newValue); // inform child
}
}
Parent.component.html
<my-child-comp [notify]="notifyObj"></my-child-comp>
Child.component.ts
export class ChildComp implements OnInit{
@Input() notify = new Notifier(); // create object to satisfy typescript
ngOnInit(){
this.notify.valueChanged = (d: number) => {
console.log(`Parent has notified changes to ${d}`);
// do something with the new value
};
}
}
Related videos on Youtube
Comments
-
shammelburg almost 2 years
I have created a child component which has a method I want to invoke.
When I invoke this method it only fires the
console.log()
line, it will not set thetest
property??Below is the quick start Angular app with my changes.
Parent
import { Component } from '@angular/core'; import { NotifyComponent } from './notify.component'; @Component({ selector: 'my-app', template: ` <button (click)="submit()">Call Child Component Method</button> ` }) export class AppComponent { private notify: NotifyComponent; constructor() { this.notify = new NotifyComponent(); } submit(): void { // execute child component method notify.callMethod(); } }
Child
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'notify', template: '<h3>Notify {{test}}</h3>' }) export class NotifyComponent implements OnInit { test:string; constructor() { } ngOnInit() { } callMethod(): void { console.log('successfully executed.'); this.test = 'Me'; } }
How can I set the
test
property as well?-
Damjan Pavlica about 6 yearsPossible duplicate of Call a method of the child component
-
Muhammad Mabrouk almost 4 yearsYou can check this answer here: stackoverflow.com/a/53057589/6663458
-
-
Waleed Shahzaib over 6 yearsWhat is ChildVM in this line: @ViewChild(ChildComponent ) child: ChildVM;
-
Waleed Shahzaib over 6 yearsI followed your approach, but I'm getting error while using directives: [ChildCmp], The error says: directives' does not exist in type 'Component'. I've googled it and found directives is deprecated in rc5. So how to handle it on the newer version. Please help.
-
rashfmnb over 6 yearstry this link angular.io/guide/component-interaction and comment the directives link
-
Anandhu Ajayakumar about 6 yearsHow to make it work when there is multiple children of same class??
-
Ajeet Shah about 6 years@WaleedShahzaib I think OP meant
ChildComponent
byChildVM
-
Alexei - check Codidact almost 6 yearsIt is an elegant solution, however it does not work properly in all cases, probably due Angular change detection not working from subscribe.
-
tatsu over 5 yearsI thought this would create a separate instance of the component but it actually calls the function from your instance with it's variables in the current state of that component, holy cow! this method is way better than the first answer!
-
Weston over 5 yearsFound this to be the best solution for my use case. Works like a charm. Thanks!
-
Trilok Pathak over 5 years@rashfmnb "Declaration expected". An error is coming when I try to write @ViewChild('child') child:ChildCmp;in the component. Please help! And Also i cannot import the same in the directive it gives me error like "directive: (typeof EmployeeProfileC...' is not assignable to parameter of type 'Component'. Object literal may only specify known properties, and 'directive' does not exist in type 'Component'."
-
shr over 5 yearsNeat ! For simpler cases, you can avoid the Subject/Subscribe overhead by passing an object that has a callback method to the child. Similar to the above, the child overrides the callback to receive indications from the parent.
-
Ambuj Khanna over 5 yearsI am always getting Undefined value of "this.child"
-
Imad El Hitti over 5 years@shr any chance you can share your solution to pass an object with callback ?
-
shr over 5 years@ImadElHitti, added a sample solution as a separate answer, since code is not allowed within comments.
-
Kelvin Low about 5 yearsI have the same problem as @AmbujKhanna
-
tony about 5 yearsMy guess for 'this.child' being undefined is that either ViewChild is pointing at something that doesn't exist in the template, or you are trying to access it too early in the lifecycle, e.g. in the constructor.
-
canbax almost 5 yearsOK but we also want to do it programmatically using ts
-
Gil Epshtain over 4 yearsFor use from within the component:
@ViewChild('appChild', { static: false }) appChild: ElementRef<HTMLElement>;
and later usethis.appChild.doSomething()
-
VIKAS KOHLI over 4 yearsThis one is elegant solution, this should be the accepted answer, just change import method like import {Subject} from 'rxjs';
-
Tanzeel over 4 yearsI'm using your answer with type selector. It worked! :-)
-
Berk Kurkcuoglu about 4 yearsA subject is not necessarily required here because it is a one-way relationship, an EventEmitter would be sufficient for this job.
-
Bogdan D almost 4 yearsThis a correct answer, but it produces tightly coupled components. A better pattern is to use
Input
properties: an observable to which the child reacts by calling its own internal function. See user6779899 's answer -
Bogdan D almost 4 yearsNice, I was looking for something like this, it's a loosely coupling approach. However, the subject in child should be only an
Observable
, the child must not be able to emit events. -
Sathiamoorthy almost 3 yearsthis is the best answer.
-
Adnan Fayaz almost 3 yearsThere was no need to explicitly call the ngAfterViewInit(). it will be called automatically if implemented on the class
-
lwairore almost 3 yearsThere's a need to explicitly call the
ngAfterViewInit()
because we explicitly need to tell Angular to call methodstartTimer()
, which is in componentCountdownTimerComponent
-
Shadoweb over 2 yearsThis is indeed the best solution as ViewChild won't work with content projection, you'll have to use ContentChild instead and after a while it can be complex to know which use case, while Subject is consistant.
-
Mateen about 2 yearsNullInjectorError: No provider for ChildComponent!