0

I have 2 components b,c on the same level contained in a

a
 b
 c

c has raises events using EventEmitter eC in Output() that I want to consume in b. As I cannot "directly" feed that to b, I "redirected" those events by creating another EventEmitter eA that lives in a, that just replays incoming events eC. Then I pass this EventEmitter as an Input() to b:

//b
  @Input() public reloadRequested: EventEmitter<void>;
  ngOnInit() {
    this.reloadRequested.subscribe(() => {
...
    });
  }

Is there anything wrong this approach? I was wondering because I basically did not find anything during my online researches. How would you do this otherwise?

UPDATE: I don't want to pass data to a component but an event. Using the Input() Decorator, referencing an EventEmitter of the parent component, seems to be the obvious way for me.

2 Answers 2

1

The usual way of doing this is, with keeping the rest of the setup the same (component C emits events, parent A handles the events), is: patch values (not event emitter/observable) as input to component B, and in B either use ngOnChanges hook or a setter input:

ngOnChanges(changes: SimpleChanges): void {
    if (changes.someInput) {
// do stuff with this.someInput
    }
}

or

@Input set() someInput (value: any) {
// do stuff with `value`
}

MAJOR EDIT: but considering that C isn't emitting any values that we care about, we care only about the fact of emission itself, this isn't the right pattern. Your approach with observable input is sound, just a small improvement: the parent doesn't actually have to do anything, certainly not create another observable. All the necessary building blocks are there, just glue them together in the template:

<app-c #thatButton></app-c>
<app-b [foo$]="thatButton.foo"></app-b>

Stackblitz:

https://stackblitz.com/edit/angular-simple-changes-utvl61?file=src%2Fapp%2Fb%2Fb.component.ts

4
  • okay so instead of replaying events of C using another eventemitter in A you would change input data of B. okay I can see how this works but this doesn't look elegant to me. I still wonder how my approach isn't the obvious one to be honest?
    – yBother
    Commented Aug 16, 2023 at 8:28
  • ... mapping an event<void> to input data is even more confusing since you would need to map it to a boolean which does not represent an event<void> very well.
    – yBother
    Commented Aug 16, 2023 at 8:35
  • @ybother OK, if C's emissions are void, that would not be the good approach (still could make it work, but it would be hacky). Edited my answer.
    – mbojko
    Commented Aug 16, 2023 at 9:36
  • 1
    thanks for showing me how to "glue them" together. I really was worried about that redirecting of events instead of directly using them
    – yBother
    Commented Aug 16, 2023 at 9:50
0

From the docs

Use in components with the @Output directive to emit custom events synchronously or asynchronously, and register handlers for those events by subscribing to an instance. EventEmitter

also

Extends RxJS Subject for Angular by adding the emit() method. EventEmitter

So it really looks like the are just a Subject with only one purpose: Output data from a component so i would use them just for this.

I usually subscribe the eventEmitter in the parent, store the data in a variable and send it to the Input of the other child components.

Everything should refresh automatically.

3
  • Yes I know that, but I don't want to send data to a component but an event (in this case even void). this also allows for the component to react on the incoming events in various ways e.g using rxjs.
    – yBother
    Commented Aug 16, 2023 at 8:19
  • 1
    Did you consider to use a service?
    – giacomoto
    Commented Aug 16, 2023 at 8:23
  • actually just came across this: angular-book.dev/ch07-03-service-events.html which seems kind of overkill for just 2 sibling components.
    – yBother
    Commented Aug 16, 2023 at 8:28

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.