Reputation: 4517
How to call main component function from a child component when I have deep nested hierarchy?
I have 3 components, button component I'm including inside browser component and browser component I'm including inside main component.
On click of button I need to call a function which is inside 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();
}
}
button component html
<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;
}
browser component html
<div>
<h1>browser title</h1>
<cb-button (click)="editCampus()"></cb-button>
</div>
and finally in main component i'm including browser component
main-component.ts
editCampus() {
alert('clicked');
}
html
<topology-browser [campus]="campus"></topology-browser>
when I click button I'm getting below error
Errorself.parentView.context.editCampus is not a function
Upvotes: 3
Views: 1561
Reputation: 41571
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 parent Main component
<topology-browser [campus]="campus" (buttonClick)="buttonComponentClicked($event)"></topology-browser>
Component code
buttonComponentClicked(buttonClicked){
/// method calls goes her
}
By this way you are notifying the browser component with the click which is captured again in the main component and handled
Upvotes: 0
Reputation: 38191
As I know there are two ways for your situation:
inject
the parent component to child componentEventEmitter
Since you have more than two layers, injecting MainComponent
to ButtonComponent
is much more simply to implement:
import {Component, Inject, forwardRef} from '@angular/core';
// change the MainComponent to your real component name
constructor(@Inject(forwardRef(() => MainComponent)) private main:MainComponent)
Upvotes: 2
Reputation: 657691
If you don't know what type in advance but you can customize the root component to your needs, a shared service is a good way.
A more generic way is to get the root component by injecting ApplicationRef
(not actually tested myself):
constructor(app:ApplicationRef, injector: Injector) {
app.components[0].someMethodOnMainComponent();
}
https://angular.io/docs/ts/latest/api/core/index/ApplicationRef-class.html
Upvotes: 3
Reputation: 773
You may try the below. I have not tried this but am guessing it might work. The button component emits an event which is being caught by the main component.
You may also pass data via a common service and injecting that service into the child component and calling a service function which updates a service observable which is subscribed by the main component
Your 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>
Upvotes: 0