Angular Component Communication — Simple yet Powerful Way
Hello,
Lately, I was working on a project where we had too many component communication requirements.
The following were the possible solutions to achieve our goals:
- Parent/Child components could communicate using @Input and @Output
- Using the RxJs’s Subjects for component communication, not having the parent/ child relationship
We proceeded with creating Input/Output’s and Subjects, but later in the development cycle, we realized that we ended up having too many Input/Outputs and Subjects created and listener for each type of communication we had.
To simplify this equation a bit, we created a simple yet powerful service to handle the component communication. The idea was, instead of creating multiple Subject or Input/output setups, to create one service that can broadcast messages to all of the listeners, and observers can decide if the broadcasted message is interesting or not.
Here we go, ‘event.service.ts’:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
export interface IMessageProps<T> {
action: string;
payload: T;
}
@Injectable()
export class EventService {
// Subject subscription
private _message = new Subject();
get message() {
return this._message.asObservable();
}
constructor() { }
// Subject broadcast
broadcast<T = any>(action: string, payload: T = null) {
this._message.next({
action: action,
payload: payload
});
}
}
Key Points
- If you look closely, it’s following the terminology from the Redux world, i.e. action and payload.
- Each broadcasted message will carry the message information.
- Observers listening to the messages can process the messages useful to them.
Broadcasting a Message
Broadcasting a message is as simple as calling a method on the event service with the required information.
// Angular imports and metadata goes here...
class PublisherComponent {
constructor(private eventService: EventService) {}
deleteUser() {
this.eventService.broadcast({
action: 'DELETE_USER',
payload: {
Id: 123
}
});
}
}
As we see here, we are calling the broadcast message as defined in the interface IMessageProps
. We are defining the message/action type and the payload to process that message.
Listening to the Message
As our event service is nothing but the RxJs’s Subject, listening/subscribing to Subject should be simple enough.
// Angular imports & metadata goes here...
class SubscriberComponent implements OnInit, OnDestroy {
eventSubscription: Subscription;
constructor(private eventService: EventService) {}
ngOnInit() {
this.eventSubscription = this.eventService.message.subscribe(
(message: IMessageProps) => {
switch (message.action) {
case 'DELETE_USER':
this._deleteUser();
break;
}
}
);
}
ngOnDestroy() {
this.eventSubscription.unsubscribe();
}
private _deleteUser() {
// your code goes here
}
}
As we see here, the Subscriber component is listening to the messages, and if the broadcasted message is of type DELETE_USER
, that will be processed. The rest all will be ignored (simply because the listener component is not interested in the rest of the messages).
And that’s it. We are done. We have component communication that is much simpler, more organized, and easier to understand.
Let me know your thoughts on it.
Connect with me at:
Twitter: https://twitter.com/mkdudeja
LinkedIn: https://www.linkedin.com/in/mkdudeja/
Thanks,
Manish K. Dudeja
Top comments (3)
Maybe you could try NgRx for this cases. I think losing typechecking (because you can't check the actions or if you want to the combination of actions/payloads would probably end up the same way as NgRx manage them.
Ngrx undoubtedly a great tool, but as the saying is, "Great power comes at some cost." Ngrx will cause lots of boilerplate code to be setup in terms of actions, reducers, effects for every feature.
Might not be good fit for small to mid-size apps. This post as the title says, "simple yet powerful way" tries to use the same principle for component communication without adding too much of code or additional library in the codebase and best suited for all size of projects.
I don't think that if you need and event system the app is small to mid in size. Also, have you checked out NgRx lately? They have updated the tooling and the boilerplate has become minimal for most of things.