liveBook · Manning

State management

As explained in Modern Angular

State management is the practice of storing, updating, and sharing application state across software components.

State management stores data that changes over time and shares it across multiple parts of an Angular application. Older applications commonly place a Subject or BehaviorSubject in a service, allowing several components to subscribe to the same state. Dedicated libraries such as NgRx and NGXS build similar data-exchange systems on RxJS. section 5.2 section 1.2.1

Signals offer a lightweight alternative for application-specific shared state. Because signals notify consumers when updated, a service can own data and behavior for a feature while exposing reactive values to multiple components. This keeps state-related work out of components without requiring a dedicated state-management library. section 7.3 section 7.3.4

A signal-based service can separate reactive state from event streams:

  • Represent current, derived application data with signals, such as an array of time-off requests and filtered or resolved requests. section 7.3.4
  • Represent user actions such as approving, rejecting, or deleting a request as RxJS Subject event streams. section 7.3.4
  • Convert and combine those streams so events update the signal-based state in one direction. section 7.3.4
  • Inject the service into components, bind its signals in templates, and delegate user actions back to service methods. section 7.3.4

Time-off request service

A TimeOffManagementService centralizes time-off request data, selected request type, and approval, rejection, and deletion behavior. The component exposes the service’s request signals locally and forwards action methods, so it needs no template changes while becoming shorter and easier to understand and test. section 7.3.4 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);
  }
}

The listing shows a root-provided service that combines a selected-type signal with RxJS action streams to derive request state. section 7.3.4

Listing 7.14 State management with signals used in a component
export class TimeOffManagementComponent {
  private readonly timeOffsService = inject(TimeOffManagementService);
  requests = this.timeOffsService.requests;
  resolvedRequests = this.timeOffsService.resolvedRequests;
  selectedType = this.timeOffsService.selectedType;

  approveRequest(request: TimeOffRequest) {
    this.timeOffsService.approveRequest(request);
  }

  rejectRequest(request: TimeOffRequest) {
    this.timeOffsService.rejectRequest(request);
  }

  deleteRequest(request: TimeOffRequest) {
    this.timeOffsService.deleteRequest(request);
  }
}

The component listing shows the intended boundary: read signals from the service and delegate request actions to it. section 7.3.4

How Modern Angular covers it

How deep it goes
Works through a signal-and-RxJS service implementation, including derived request state, event streams, and component delegation.
Examples
Uses authentication status and an HR time-off workflow with filtering, approval, rejection, deletion, and a TimeOffManagementComponent.
What it assumes
Assumes Angular components, services, dependency injection, signals, and basic RxJS observables and subjects.
What you can do after
Build it from scratch as a lightweight signal-based service that handles event streams and exposes shared reactive state.
How it connects
Connects signals, RxJS, observables, Subjects, BehaviorSubject, NgRx, change detection, and unit testing.

Also explained in

Compare how 9 books explain state management →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern Angular. The section links point to the parts of the book it draws on.