Búsqueda de sitios web

javascript - ¿Cómo emitir un evento desde los nietos hasta el abuelo en Angular moderno?


Si tengo varios niveles de componentes Angular, ¿cómo puedo usar @Output para emitir un evento desde un hijo hasta el abuelo?

Abuelo/a:

<parent (handleClick)="grandmaHandleClick($event)">
<parent>
...
grandmaHandleClick(event) {
  console.log('grandma knows you clicked')
}

Padre:

<child (handleClick)="handleClick($event)">
</child>

Niño :

<div (click)="onClick()">Click button
</div>
...
@Output() handleClick = new EventEmitter
onClick() {
  this.handleClick.emit('clicked a button')
}

Estoy tratando de hacer que @Output pueda pasar propiedades a través de varios componentes, ¿cuál es la mejor manera de lograr esto y puedes proporcionar un ejemplo?

Respuesta #1

Podría haber 2 maneras:

  1. Usando @output:

Abuelo/a

<parent (notifyGrandParent)="grandmaHandleClick($event)">
<parent>
...
grandmaHandleClick(event) {
  console.log('grandma knows you clicked')
}

Padre:

<child (handleClick)="childEvent($event)">
</child>

@Output() notifyGrandParent= new EventEmitter();
childEvent(event) {
  this.notifyGrandParent.emit('event')
}

Child está implementado correctamente en el código, por lo que está listo para usar.

  1. Usando BehaviorSubject a través de Service: Con este nivel de anidamiento, en realidad puedes crear un servicio como EventService, y luego crear un BehaviorSubject al que el Abuelos puede suscribirse directamente. Además, para hacer que este servicio sea más específico de un componente, puedes mantener este servicio en un módulo que tendrá otros 3 componentes (Abuelo, Padre y Hijo)
export class EventService{

 private childClickedEvent = new BehaviorSubject<string>('');

  emitChildEvent(msg: string){
     this.childClickedEvent.next(msg)
  }

  childEventListner(){
     return this.childClickedEvent.asObservable();
   } 

}

y luego en components:

ComponenteHijo

export class ChildComponent{
   constructor(private evtSvc: EventService){}

   onClick(){
     this.evtSvc.emitChildEvent('clicked a button')
   }
}

Abuelo

export class GrandComponent{
   constructor(private evtSvc: EventService){}

   ngOnInit(){
     this.evtSvc.childEventListner().subscribe(info =>{
         console.log(info); // here you get the message from Child component
      })
   }
}

Tenga en cuenta que, con el evento @output, se crea un acoplamiento estrecho de componentes y, por lo tanto, se genera una fuerte dependencia (padre-hijo-nieto). Si el componente no es reutilizable y solo se crea para cumplir este propósito, entonces @output también tendrá sentido porque transmitirá el mensaje a cualquier nuevo desarrollador de que tienen una relación padre-hijo.

Crear un servicio para pasar datos también expone los datos a otros componentes que pueden inyectar service en constructor.

Entonces, la decisión debe tomarse en consecuencia.

Respuesta #2

Usa rxjs/subject, puede ser observador y observable al mismo tiempo.

Uso :

  1. Crear propiedad Subject en el servicio:
import { Subject } from 'rxjs';

export class AuthService {
  loginAccures: Subject<boolean> = new Subject<boolean>();
}
  1. Cuando ocurre un evento en la página/componente hijo, usa:
logout() {
  this.authService.loginAccures.next(false);
}
  1. Y suscríbete al tema en la página/componente principal:
constructor(private authService: AuthService) {
  this.authService.loginAccures.subscribe((isLoggedIn: boolean) => {
    this.isLoggedIn = isLoggedIn;
  })
}

Artículos relacionados