nakajuice
nakajuice

Reputation: 692

Emit event through nested components in Angular2

One can use Output() decorator to emit the event from the child component so that the parent component can catch it. What I need is to catch an event emitted by any child component, which is not necessarily a direct child of a given component.

Let ComponentTwo be a component which emits the event. If the app has the following structure: App -> ComponentTwo, then we can easily catch the event emitted by ComponentTwo. But if we consider structure like App -> ComponentOne -> ComponentTwo, then we can't catch the emitter directly.

Here is a plunker that illustrates the problem.

So is there a way to sort of propagate event to all parent components? Thanks.

Upvotes: 16

Views: 18703

Answers (3)

Simon_Weaver
Simon_Weaver

Reputation: 146218

If you find you have to pass certain events through make sure to be consistent and come up with a naming strategy. For instance I like to add raise to the beginning of the method name if the only thing that method does is to re-raise an event.

eg.

(paypalTokenized)="raisePaypalTokenized($event)"

and in the ts file:

@Output('paypalTokenized')
public paypalTokenizedEmitter = new EventEmitter<PayPalTokenizedPayload>();

// PayPal tokenized
public raisePaypalTokenized(payload: PayPalTokenizedPayload)
{
    // no other logic here!
    this.paypalTokenizedEmitter.emit(payload);
}

This means I can tell immediately that the event is being passed through with no further action.

Upvotes: 1

Emmanuel de Arzave
Emmanuel de Arzave

Reputation: 33

the thierry answer is the correct aproach, but if you want to avoid use shared service, you can do somthing like this

view.html

<componentA
   (actionA)=actionHandler($event)
>
</componentA>

view.ts

actionHandler(event){
  //doSomething
}

componentA.html

<componentB
   (actionB)=actionHandlerA($event)
>
</componentB>

componentA.ts

@Output() actionA: EventEmitter<{}> = new EventEmitter();

constructor() {
}

actionHandlerA(event){
  this.actionA.emit(event);
}

componentB.html

<a (click)="actionHandlerB(...)" >click me</a>

componentB.ts

@Output() actionB: EventEmitter<{}> = new EventEmitter();

constructor() {
}

actionHandlerB(o: objectModel){
  this.actionB.emit(new objectModel(o));
}

Upvotes: 0

Thierry Templier
Thierry Templier

Reputation: 202346

There is no support of bubbling for such events. You need to manually catch them and emit to the parent.

Another approach would be to leverage a shared service for this tree of components and use an observable / subject in it.

This way all components can subscribe on it to be notified of events even within sub sub children.

constructor(private service: SharedService) {
  this.service.notifier$.subscribe(
    data => {
      (...)
    });
}

The event will be triggered this way:

constructor(private service: SharedService) {
}

notify() {
  this.service.notifier$.next('some data');
}

See this link for more details:

Upvotes: 27

Related Questions