How to emit an event from grandchildren to grandparent in modern angular?
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 are not reusable and are 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.
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; })}