How to emit an event from grandchildren to grandparent in modern angular?
Solution 1
There could be 2 ways:
- Using
@output
:
Grandparent
<parent (notifyGrandParent)="grandmaHandleClick($event)">
<parent>
...
grandmaHandleClick(event) {
console.log('grandma knows you clicked')
}
Parent:
<child (handleClick)="childEvent($event)">
</child>
@Output() notifyGrandParent= new EventEmitter();
childEvent(event) {
this.notifyGrandParent.emit('event')
}
Child is implemented properly in the code so it is good to go.
- Using
BehaviorSubject
viaService
: With this much level of nesting, you can actually create some service likeEventService
, and then createBehaviorSubject
which can directly be subscribed by the GrandParent. Also, to make thisservice
more component specific, you can keep this service in amodule
which will have other 3 components (GrandParent, Parent and Child)
export class EventService{
private childClickedEvent = new BehaviorSubject<string>('');
emitChildEvent(msg: string){
this.childClickedEvent.next(msg)
}
childEventListner(){
return this.childClickedEvent.asObservable();
}
}
and then in components
:
ChildComponent
export class ChildComponent{
constructor(private evtSvc: EventService){}
onClick(){
this.evtSvc.emitChildEvent('clicked a button')
}
}
GrandParent
export class GrandComponent{
constructor(private evtSvc: EventService){}
ngOnInit(){
this.evtSvc.childEventListner().subscribe(info =>{
console.log(info); // here you get the message from Child component
})
}
}
Please note that, with @output
event, you create a tight coupling of components and so a strong dependency (parent-child-grandchild) is created. If the component is not reusable and is only created to serve this purpose, then @output
will also make sense because it'll convey the message to any new developer that they have parent-child relationship.
Creating a service to pass data also exposes the data to other components which can inject service
in constructor
.
So, the decision should be taken accordingly.
Solution 2
Use rxjs/subject, it can be observer and observable in the same time.
Usage:
- Create Subject property in service:
import { Subject } from 'rxjs';
export class AuthService {
loginAccures: Subject<boolean> = new Subject<boolean>();
}
- When event happens in child page/component use:
logout() {
this.authService.loginAccures.next(false);
}
- And subscribe to subject in parent page/component:
constructor(private authService: AuthService) {
this.authService.loginAccures.subscribe((isLoggedIn: boolean) => {
this.isLoggedIn = isLoggedIn;
})
}
Related videos on Youtube
user2167582
Updated on October 03, 2022Comments
-
user2167582 over 1 year
If I have multiple levels of angular components, how can I use
@Output
to emit an event from child to the grand parent?Grandparent:
<parent (handleClick)="grandmaHandleClick($event)"> <parent> ... grandmaHandleClick(event) { console.log('grandma knows you clicked') }
Parent:
<child (handleClick)="handleClick($event)"> </child>
Child:
<div (click)="onClick()">Click button </div> ... @Output() handleClick = new EventEmitter onClick() { this.handleClick.emit('clicked a button') }
I am trying to have it so that @Output can prop drill a few components deep, whats the best way to accomplish this, and can you provide example?
-
user2167582 almost 5 yearsIn the first approach, wouldn' @output be on the child component?
-
Shashank Vivek almost 5 years@user2167582: It has already been handled by you properly using
@Output() handleClick
inchild component
that is why I didnt mention it. Let me add that as well -
user2167582 almost 5 yearsThank you, I did and it works. upon asking this I was also curious if there's a way to pass (boundedEvent) down components without necessarily having to add handler methods to emit back up the hierarchy, seems like it is needed.
-
Shashank Vivek almost 5 years@user2167582: If its just one level of
parent
child
components, you can use@Input
and usengOnChange
in child to monitor the change in value which is passed tochild component
. Else, if its is multi level component structure, you can again useBehaviorSubject
-
David Silva over 3 yearsThis was so helpful to me. Just a tiny detail.... In the original post there's the line...
<div (click)="onClick">Click button</div>
. TheonClick
should beonClick()
. The answer says, "Child is implemented properly in the code so it is good to go" -- so someone might end up confused. -
Shashank Vivek over 3 years@DavidSilva: You are correct, my friend! I'll correct that in the question. Many Thanks ! :)