Angular2: how to call main component function from child component
How do I call a main component function from a child component when I have a deep nested hierarchy?
I have 3 components, a button component in which I include a browser component and a browser component that I include in a main component.
When the button is clicked, I need to call a function that is inside the main component.
Button component
@Component({
selector: 'cb-button',
templateUrl: 'cb-button.component.html',
styleUrls: ['cb-button.component.scss']
})
export class CbButtonComponent {
@Output() onClick: EventEmitter<any> = new EventEmitter();
onBtnClick(): void {
this.onClick.emit();
}
}
html button component
<div (click)="onBtnClick()">
<button>btn</button>
</div>
browser component
@Component({
selector: 'topology-browser',
templateUrl: 'topology-browser.component.html',
styleUrls: ['topology-browser.component.scss']
})
export class TopologyBrowserComponent {
@Input('campus') campus: Campus;
}
html browser component
<div>
<h1>browser title</h1>
<cb-button (click)="editCampus()"></cb-button>
</div>
and finally in the main component I include the browser component
<strong> core-component.ts
editCampus() {
alert('clicked');
}
Html
<topology-browser [campus]="campus"></topology-browser>
when i click the button i get below error
Errorself.parentView.context.editCampus is not a function
source to share
- If you know what type of root component is, you can use the Pengyy method.
-
If you don't know which type beforehand, but you can customize the root component to suit your needs, a generic service is a good way to go.
-
A more general way is to get the root component by injecting
ApplicationRef
(not actually tested by itself):
constructor(app:ApplicationRef, injector: Injector) { app.components[0].someMethodOnMainComponent(); }
https://angular.io/docs/ts/latest/api/core/index/ApplicationRef-class.html
source to share
As I know there are two possibilities for your situation:
-
inject
parent component for child component - use
EventEmitter
Since you have more than two levels, nesting MainComponent
in is ButtonComponent
much easier to implement:
import {Component, Inject, forwardRef} from '@angular/core';
// change the MainComponent to your real component name
constructor(@Inject(forwardRef(() => MainComponent)) private main:MainComponent)
source to share
export class CbButtonComponent {
@Output() onClick: EventEmitter<string> = new EventEmitter<string>();
onBtnClick(): void {
this.onClick.emit('clicked');
}
}
In your browser component
Html
<div>
<h1>browser title</h1>
<cb-button (onclick)="buttonclicked($event)"></cb-button>
</div>
Component
@Output() buttonClick: EventEmitter<string> = new EventEmitter<string>();
buttonclicked(clickedEvent){
this.buttonClick.emit('clicked');
}
In your main component
<topology-browser [campus]="campus" (buttonClick)="buttonComponentClicked($event)"></topology-browser>
Component code
buttonComponentClicked(buttonClicked){
/// method calls goes her
}
This way you notify the browser component with a click, which is captured again in the main component and processed
source to share
You can try the following. I haven't tried this, but I think it might work. The button component fires an event that is captured by the main component.
You can also pass data through a generic service and inject that service into a child component and call a service function that updates the observable service that is subscribed by the main component
Main component
@Component({
template `
<button-comp (onClick)="mainMethod($event)"></button-comp>
`,
directives: [ ButtonComponent ]
})
export class MainComponent {
(...)
mainMethod(event) {
console.log(event)
}
}
your button component
@Component({
selector: 'cb-button',
templateUrl: 'cb-button.component.html',
styleUrls: ['cb-button.component.scss']
})
export class CbButtonComponent {
@Output() onClick: EventEmitter<any> = new EventEmitter();
onBtnClick(): void {
this.onClick.emit('hello');
}
}
button component html
<div (click)="onBtnClick()">
<button>btn</button>
</div>
source to share