Angular Signals State Management
Relevant source files
The following files were used as context for generating this wiki page:
- best-practices.md
- implementation_plan.md
- sunrise-angular/src/app/core/services/product.service.ts
- sunrise-angular/src/app/shared/components/requirement-estimator/requirement-estimator.component.ts
- sunrise-angular/src/app/pages/guides/guide-detail/guide-detail.component.ts
- sunrise-angular/src/app/app.ts
Angular Signals serve as the primary mechanism for state management within the Sunrise Communication project. This architecture replaces traditional reactive patterns with a fine-grained, signal-based approach to track data changes and optimize rendering. The project utilizes signals for local component state, derived values through computed signals, and global service-level state.
Sources: best-practices.md:10, implementation_plan.md:20
State Management Architecture
The project follows a specific hierarchy for managing data flow. Local component state is handled via signal(), while complex derived logic uses computed(). For state that depends on multiple reactive sources and requires synchronization, the architecture employs linkedSignal().
Core Signal Types
| Signal Type | Usage | Project Implementation Example |
|---|---|---|
signal<T> | Writable state for local or service data. | currentStep = signal<number>(1) |
computed<T> | Read-only derived state that auto-updates. | recommendedNvr = computed(() => ...) |
input<T> | Signal-based component inputs. | product = input.required<Product>() |
output<T> | Signal-based event emitters. | Used for component communication. |
Sources: best-practices.md:22-30, sunrise-angular/src/app/shared/components/requirement-estimator/requirement-estimator.component.ts:18
Service-Level State Flow
Global state, such as product catalogs or SEO metadata, is managed within services using a private-writable and public-readonly pattern. This ensures data integrity by preventing external components from directly mutating service state.
The diagram shows the flow from private service state to public signals consumed by components to create derived view state.
Sources: implementation_plan.md:144-162
Reactive Patterns and Best Practices
The implementation adheres to strict guidelines to maintain performance and predictability. Developers must use update or set methods instead of mutate when modifying signal values. For components, changeDetection: ChangeDetectionStrategy.OnPush is the default behavior in the project's Angular version (v22+), which complements the signal-based reactivity.
Implementation Guidelines
- Pure Transformations: Keep state transformations within
computed()signals pure and predictable. - Async Handling: Prefer the
asyncpipe or direct signal access in templates over manual subscriptions. - Two-Way Binding: Use the
model()function for properties requiring two-way binding ([(prop)]syntax). - Performance: Avoid complex logic inside templates; move calculations to
computed()signals in the TypeScript class.
Sources: best-practices.md:13-14, best-practices.md:33-36
Functional Component State
Components like the RequirementEstimatorComponent demonstrate complex signal usage by deriving technical recommendations from user-defined parameters.
// Example from requirement-estimator.component.ts
cameraCount = signal<number>(8);
storageDays = signal<number>(30);
recommendedHdd = computed(() => {
const cams = this.cameraCount();
const days = this.storageDays();
const estTb = Math.ceil((cams * 20 * days) / 1000);
const standardSizes = [2, 4, 6, 8, 12, 16, 24];
const match = standardSizes.find(s => s >= estTb) || standardSizes[standardSizes.length - 1];
return `${match} TB Surveillance Grade HDD`;
});
Side Effects with effect()
The project uses the effect() function for operations that must run when signal values change but are not part of the data transformation flow, such as updating SEO tags or interacting with the DOM.
The sequence diagram illustrates how an effect() in GuideDetailComponent triggers SEO updates whenever the underlying guide signal changes.
Sources: sunrise-angular/src/app/pages/guides/guide-detail/guide-detail.component.ts:42-50
Integration with Routing
Signals are synchronized with the Router to maintain shareable application states. For example, product filters are stored in signals but mirrored to URL query parameters. Upon initialization, the component reads the ActivatedRoute parameters and sets the corresponding signals, ensuring the UI remains in sync with the URL.
Sources: implementation_plan.md:239-251, sunrise-angular/src/app/pages/guides/guide-detail/guide-detail.component.ts:53-66
Angular Signals State Management in this project provides a robust, type-safe, and performant way to handle both local and global data. By leveraging computed() for derived logic and effect() for side effects, the architecture ensures that the UI stays synchronized with the underlying data model with minimal manual intervention.