In Angular 8
, I use the following approach in order to refresh Details
page after a new record added:
EventProxyService
export class EventProxyService {
private eventTracker = new BehaviorSubject<any>(undefined);
/* Allows subscription to the behavior subject as an observable */
getEvent(): BehaviorSubject<any> {
return this.eventTracker;
}
/* Allows updating the current value of the behavior subject */
setEvent(param: any): void {
this.eventTracker.next(param);
}
}
CreateComponent:
export class CreateComponent implements OnInit {
constructor(private eventProxyService: EventProxyService) { }
triggerAnEvent(param: any): void {
this.eventProxyService.setEvent(param);
}
}
DetailsComponent:
export class DetailsComponent implements OnInit {
subscription;
constructor(private eventProxyService: EventProxyService) { }
ngOnInit() {
this.subscription = this.eventProxyService.getEvent().subscribe((param: any) => {
this.theTargetMethod(param);
);
}
theTargetMethod(param) {
this.record = param; //update record via new one passed from service
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
The approach works as expected, but sometimes there are similar events e.g. Update that needs to refresh the Details
page. So, I am wondering if I should create a new BehaviorSubject
object (eventTracker
), getEvent
and setEvent
methods for each of different events e.g. Update
event? As far as I know, a single BehaviorSubject
can be used, but there may be a problem if two different events pass inconsistent data to the subscribers. What is the proper approach?
The simpliest way would be to create a type CustomEvent
(wouldn't name it Event
since that type is already used). You could either give it a field eventType
or use classes that extend from that CustomEvent
to differenciate what kind of Event is used.
eventType
fieldevents.ts
export interface CustomEvent{
eventType: 'Update' | 'OtherEvent';
data: any; // Type unsafe, maybe narrow it down
}
EventProxy
export class EventProxyService {
private eventTracker = new BehaviorSubject<CustomEvent>(undefined);
getEvent(): BehaviorSubject<CustomEvent> { return this.eventTracker; }
setEvent(param: CustomEvent): void { this.eventTracker.next(param); }
}
add/get events
// Services omitted, too long
// add new event
this.eventProxyService.setEvent({
eventType: 'Update',
data: {/* Your data here */}
});
// listen to events
this.subscription = this.eventProxyService.getEvent()
// .filter(param => param.evenType === 'Update') // if you want only specific events
.subscribe((param: CustomEvent) => {
if (param.eventType === 'Update') {
this.theTargetMethod(param);
} else if (param.eventType === 'OtherEvent') {
// do something else
}
);
events.ts
export class CustomEvent {}
export class UpdateEvent extends CustomEvent {
constructor(
public newData: Data // Use a specific type and as many fields as you need
) {}
}
export class OtherEvent extends CustomEvent {
constructor(
public otherData: OtherData// Use a specific type and as many fields as you need
) {}
}
EventProxy
export class EventProxyService {
private eventTracker = new BehaviorSubject<CustomEvent>(undefined);
getEvent(): BehaviorSubject<CustomEvent> { return this.eventTracker; }
setEvent(param: CustomEvent): void { this.eventTracker.next(param); }
}
add/get events
// Services omitted, too long
// add new event
this.eventProxyService.setEvent(new UpdateEvent({
/* Your data here */
}));
// listen to events
this.subscription = this.eventProxyService.getEvent()
// .filter(param => param instanceof UpdateEvent) // if you want only specific events
.subscribe((param: CustomEvent) => {
if (param instanceof UpdateEvent) {
this.theTargetMethod(param);
} else if (param instanceof OtherEvent) {
// do something else
}
);
EventProxy
export type EventType: 'update' | 'other';
export class EventProxyService {
// Use BehaviourSubject<SPECIFIC_TYPE> if possible
private updateEventTracker = new BehaviorSubject<any>(undefined);
private otherEventTracker = new BehaviorSubject<any>(undefined);
setEvent(type: EventType, param: any): void {
this.getEventTrackerForType(type).next(param);
}
getEvent(type?: EventType): BehaviorSubject<any> {
return this.getEventTrackerForType(type);
}
private getEventTrackerForType(type?:EventType): BehaviorSubject<any> {
switch(type) {
case 'update': return this.updateEventTracker;
case 'other': return this.otherEventTracker;
// if no type specified, return ALL events as one Observable (bonus)
default: return merge(
this.updateEventTracker,
this.otherEventTracker
)
}
}
// alternatively, create setEvent/getEvent methods for each subject specifically (setUpdateEvent/getUpdateEvent/...)
}