As pointed out by @bryan60, this question pertains more to architecture rather than a specific application state issue.
In my view, a generic approach is needed to efficiently share data across multiple components using events.
This will enable a flexible implementation that can be easily utilized throughout the application.
In my Angular app, I have employed an event service based on observables, allowing components to trigger events that other components can listen to -
Event Service
import { Injectable } from "@angular/core";
import * as Rx from 'rxjs/Rx';
import { Observable, Subject } from "rxjs/Rx";
import { UUID } from "./uuid-generator";
export const GLOBAL_EVENTS = {
Test_Event: "Test_Event";
}
/**
*
*
* @class EventListener
*/
class EventListener {
constructor(uuid: string, func: Function) {
if (!uuid || !func) {
console.error("required arguments not provided!");
return;
}
this._uuid = uuid;
this.func = func;
}
private _uuid: string;
public get uuid(): string {
return this._uuid;
}
public func: Function;
}
@Injectable()
export class EventsService {
private eventsSubject: Subject<any>;
private listeners: Map<string, Array<EventListener>>;
public constructor() {
//initialise listeners
this.listeners = new Map();
//initialise event subject
this.eventsSubject = new Rx.Subject();
//listen to the changes in subject
Rx.Observable.from(this.eventsSubject)
.subscribe(({ name, args }) => {
if (this.listeners[name]) {
this.listeners[name].forEach((listener: EventListener) => {
listener.func(...args);
});
}
});
}
/**
* Listens to the event and provides a unique key for the listener
* @method on
* @param {string} name name of the event to be listened to.
* @param {Function} listener listener function with one array argument
* @return {string} returns the key (UUID) for listener function which can be used to stop listening to the event.
* @memberof EventsService
*/
public on(name: string, listener: Function): string {
this.listeners[name] = this.listeners[name] || [];
let listenerEvent: EventListener = new EventListener(UUID.generate(), listener);
this.listeners[name].push(listenerEvent);
return listenerEvent.uuid;
}
/**
* Stops listening to the event by using the unique key for the listener
* @method off
* @param {string} name name of the event to be broadcasted
* @param {string} uuid name of the event listener specific uuid to be removed
* @param {boolean} [removeAll=false] removes all event listeners attached to specified event name
* @returns {void}
* @memberof EventsService
*/
public off(name: string, uuid?: string, removeAll: boolean = false): void {
if (!this.listeners[name] || !this.listeners[name].length) {
return;
}
if (removeAll) {
this.listeners[name] = [];
return;
}
this.listeners[name] = this.listeners[name].filter((item: EventListener, index: number) => {
return item.uuid !== uuid;
});
}
/**
* Broadcasts the event and passes data provided in args argument as event data
* @method broadcast
* @param {string} name name of the event to be broadcasted.
* @param {any} args arguments to be sent with the event.
* @return {void} return void
* @memberof EventsService
*/
public broadcast(name: string, ...args): void {
this.eventsSubject.next({ name, args });
}
}
UUID Generator
export class UUID {
public static generate(): string {
return "your_hash";
}
}
Registering Event
import { Component, OnDestroy } from "@angular/core";
import { EventsService, GLOBAL_EVENTS } from "./events.service";
@Component({
selector: "[app-listener-component]",
templateUrl: "./app-listener-component.html",
styleUrls: ["./app-listener-component.scss"]
})
export class ListenerComponent {
private eventId: string;
public constructor(private _EventsService: EventsService) {
this.eventId = this._EventsService.on(GLOBAL_EVENTS.Test_Event, (response: any) => {
console.log(response);
});
}
public ngOnDestroy(): void {
this._EventsService.off(this.eventId);
}
}
Broadcasting Message
import { EventsService, GLOBAL_EVENTS } from "./events.service";
export class BroadcatComponent
public constructor(private _EventsService: EventsService) {
let data: any = {
message: "any"
}
this._EventsService.broadcast(GLOBAL_EVENTS.Test_Event, data);
}
}
Things to Remember
Ensure to include the service in the main app module for it to function as a singleton service across the application.
Each event subscription provides a unique UUID
string that can be utilized to remove the event handler globally (
additional features are in code comments
).
Utilizing ngDestroy
to eliminate event handlers ensures that unused events do not linger in memory.
Lastly, I have made modifications to the original code, so compilation errors may arise in the sample code.
I trust this information proves useful :)