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?
To emit event from grandchild to his grandparent component with Vue. js, we call $emit in the grand child component. Then in the parent component, we pass the events from the child to the grandparent with v-on="$listeners . And then we listen to the event emitted from the grandchild component in the grandparent.
The Angular documentation says "The @Output() decorator in a child component or directive lets data flow from the child to the parent." This is exactly what we want.
While including the child component inside the parent component, bind the 'ParentId' property to the child component using property binding. Now in the child component import Input from @angular/core and create a property decorated by @input decorator to receive 'ParentId' from parent component.
concept parent component in category angularA parent component can pass data to its child by binding the values to the child's component property. A child component has no knowledge of where the data came from. A child component can pass data to its parent (without knowing who the parent is) by emitting events.
There could be 2 ways:
@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.
BehaviorSubject
via Service
: With this much level of nesting, you can actually create some service like EventService
, and then create BehaviorSubject
which can directly be subscribed by the GrandParent. Also, to make this service
more component specific, you can keep this service in a module
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.
Use rxjs/subject, it can be observer and observable in the same time.
Usage:
import { Subject } from 'rxjs'; export class AuthService { loginAccures: Subject<boolean> = new Subject<boolean>(); }
logout() { this.authService.loginAccures.next(false); }
constructor(private authService: AuthService) { this.authService.loginAccures.subscribe((isLoggedIn: boolean) => { this.isLoggedIn = isLoggedIn; }) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With