Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emit an event from grandchildren to grandparent in modern angular?

Tags:

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?

like image 342
user2167582 Avatar asked Jun 15 '19 09:06

user2167582


People also ask

How do you emit an event from a child to a grandparent?

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.

Can we pass data from child to parent in angular?

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.

How do you implement communication between child to parent element in angular?

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.

What is a parent component in angular?

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.


2 Answers

There could be 2 ways:

  1. 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.

  1. Using 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.

like image 90
Shashank Vivek Avatar answered Sep 18 '22 15:09

Shashank Vivek


Use rxjs/subject, it can be observer and observable in the same time.

Usage:

  1. Create Subject property in service:
import { Subject } from 'rxjs';  export class AuthService {   loginAccures: Subject<boolean> = new Subject<boolean>(); } 
  1. When event happens in child page/component use:
logout() {   this.authService.loginAccures.next(false); } 
  1. And subscribe to subject in parent page/component:
constructor(private authService: AuthService) {   this.authService.loginAccures.subscribe((isLoggedIn: boolean) => {     this.isLoggedIn = isLoggedIn;   }) } 
like image 38
moha noorani Avatar answered Sep 18 '22 15:09

moha noorani