An RxJS Subject is both an observable and an observer: it accepts published values and multicasts them to subscribers. In Angular, subjects support event streams and shared state that changes over time. section 5.2 section 1.2.1
Use subjects when an Angular application needs to:
- Propagate authorization events or other changes between application areas. section 1.2.1
- Represent user actions, such as approving, rejecting, or deleting a time-off request. section 7.3.4
- Centralize asynchronous work in a service while keeping consuming components small and easy to test. section 7.3.4
Time-off management service
A state-management service can expose deleteRequest$, approveRequest$, and rejectRequest$ subjects. Each event can feed an RxJS pipeline that calls the corresponding request service, while a signal stores the resulting request state. Components inject the service, read its signals, and delegate user actions back to it. section 7.3.4
Listing 7.13 State management with advanced RxJS interoperability
@Injectable({ providedIn: 'root' })
export class TimeOffManagementService {
private readonly timeOffRequestService = inject(TimeOffRequestService);
deleteRequest$ = new Subject<TimeOffRequest>(); #1
approveRequest$ = new Subject<TimeOffRequest>();
rejectRequest$ = new Subject<TimeOffRequest>();
selectedType = signal<
'Vacation' | 'Sick Leave' | 'Maternity Leave' | 'Paternity Leave' | 'Other' | ''
>((localStorage.getItem('selectedType') as any) ??
''); #2
requests = toSignal( #3
merge( #4
toObservable(this.selectedType), #5
this.deleteRequest$.pipe(switchMap((r) => this.timeOffRequestService.deleteRequest(r.id))), #6
this.approveRequest$.pipe(switchMap((r) => this.timeOffRequestService.approveRequest(r.id))),
this.rejectRequest$.pipe(switchMap((r) => this.timeOffRequestService.rejectRequest(r.id))),
).pipe(
switchMap(() => {
return this.timeOffRequestService
.getRequestsByType( #7
this.selectedType(),
);
})
),
{
initialValue: [] as TimeOffRequest[],
}
);
resolvedRequests = computed(() =>
this.requests().filter((r) => r.status !== 'Pending')
);
constructor() { #8
effect(() => {
localStorage.setItem('selectedType', this.selectedType());
});
}
approveRequest(request: TimeOffRequest) {
this.approveRequest$.next(request); #9
}
rejectRequest(request: TimeOffRequest) {
this.rejectRequest$.next(request);
}
deleteRequest(request: TimeOffRequest) {
this.deleteRequest$.next(request);
}
}
Inspect the complete state-management listing to see subjects connected to request operations and signal-based state. section 7.3.4
