Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
What Is State in Angular and Where Should It Live? Separating Server, UI, URL and Form State
Where state lives is decided by two questions: who owns the data (the API, the address bar, the browser) and how long it must live; server state goes in a resource, URL state in a query param, local state in the component, shared client state in a service, and derived values are never stored. On Bookstore's catalog page we show with a real run what happens to the four kinds on Back and on reload, and prove that copying the API response into a global store shows stale stock.
Signal-Based Service State: Writing a Store with Read-Only Signals, computed and Angular 22's @Service() Decorator
A library-free Angular store is a private writable signal, a read-only view exposed with asReadonly(), derived values with computed and methods that update state immutably; its lifetime is set by the injector that provides it. We write Bookstore's cart with Angular 22's @Service() decorator and show with real output what an update returning the same array, a route-level store without withAutoCleanupInjectors() and an effect writing its own signal actually do.
Managing Server State: resource, httpResource, chain() and Invalidation After Mutations
In Angular 22, server state is managed with the resource family, which carries the loading, error, reloading and local statuses itself: read with httpResource, write with HttpClient, and refresh the resource with reload() after a mutation. On Bookstore's book page we show with real output dependent resources with chain(), an optimistic review with rollback, two components fetching the same list, NgRx 22's withPreviousValueOnLoading and what reading value() in error does.
Using the URL as State: Query Params, withComponentInputBinding and a Working Back Button
Filters that must be shareable, survive a reload and work with Back belong in the URL: query params are bound to inputs with withComponentInputBinding(), validated with transform and changed only through router.navigate. We move Bookstore's catalog to the URL and show with real output a shared link, invalid values, the Back button, how replaceUrl keeps the history clean in a search box, and Angular 22's 'always' paramsInheritanceStrategy.
Getting Started with NgRx Signal Store: signalStore, withState, withComputed, withMethods and patchState
NgRx Signal Store provides the parts of a hand-written signal store as ready-made features: withState for state signals, withComputed for derived values, withMethods and patchState for immutable updates, withProps and withHooks for dependencies and lifecycle. We convert Bookstore's cart and checkout without changing component code and show with real output protected state, private members, NgRx 22's union DeepSignal, the Map pitfall and a cart lost when the persisted shape changes.
Advanced Signal Store: withEntities, rxMethod, signalMethod, withLinkedState and Custom Store Features
The advanced parts of Signal Store take repeated work out of your stores: withEntities manages collections with updaters, rxMethod handles cancellable async work with RxJS, signalMethod does the same without RxJS, and custom features plug into any store. We move Bookstore's cart to entities, build quick search with rxMethod, add withRequestStatus() and a typed log feature using SignalStoreFeatureType, and show with real output how an error without tapResponse ends the stream.
The NgRx Signal Store Events Plugin: Event-Driven State with event, eventGroup, withReducer and withEventHandlers
The Events plugin separates "what happened" from "how state changes" in flows where several stores react to the same occurrence: a component dispatches an event, each store changes its own state with withReducer, and withEventHandlers runs side effects. In Bookstore's checkout a single orderPlaced event empties the cart, records the order and shows a notification; we compare it with a method-based version and show with real output how a store that does not exist yet misses the event.
Classic NgRx Store: createActionGroup, createFeature, Selectors, Functional Effects and DevTools
The classic NgRx Store keeps state in a single global tree and changes it only through actions: createActionGroup defines actions, createFeature the reducer and generated selectors, createSelector memoized derived data, and functional effects side effects such as HTTP. We build Bookstore's back office orders with this model and show with real output NgRx 22's DevTools actionCreators option, the bugs the ESLint rules catch, and the extra values an unmemoized selector produces.
Testing State in Angular: Signal Services, Signal Store and NgRx Store Tests
State code is tested through its public API: a Signal Store is obtained from TestBed like a service, effects are run with TestBed.tick(), HTTP is controlled with HttpTestingController and time with Vitest fake timers, while the classic Store's reducers, selectors and functional effects are tested as pure functions. We write 19 Vitest tests for Bookstore's cart, search, checkout and back office state and show with real output that an effect never runs when TestBed.tick() is forgotten.
Choosing the Right State Tool and the Evolution of Angular State: From BehaviorSubject to Signal Store
The right state tool follows from the kind of state: derived values use computed, server state a resource, shareable state the URL, and client state, depending on its scope, a signal, a signal service, Signal Store, the Events plugin or the classic Store. We sum up the choices for Bookstore's nine features, the bundle cost measured from the snapshots, the rules for dependencies between stores, NgRx Toolkit withDevtools, and the version-checked evolution from BehaviorSubject to Signal Store.