Skip to main content
cngx-src documentation

injectQueryParamSync

Functioncommon/layoutv0.1.0

projects/common/layout/router/inject-query-param-sync.ts

Description#

Bidirectional sync between a caller-owned WritableSignal<T> and a named query param. URL wins on initial load (deep-link intent); after hydrate the signal is the source and reflects outward. Re-hydrates on browser back/forward. Dev-warns once and no-ops when @angular/router is absent.

Loop-safety (the core of this helper): the reflect effect writes the URL in untracked() and skips navigate when the serialized state() equals the last value it wrote - a local closure seeded from the initial URL read, not the live URL param (the live param races the navigate-settle window). The hydrate path updates that same closure whenever it accepts a URL value, so back/forward re-hydration never triggers a reflex navigate. A param rename is migrated in one navigate ({ [old]: null, [new]: serialize(state()) }) by a dedicated effect whose only tracked source is the normalized param signal; its first run seeds bookkeeping and never navigates.

The state.set inside the hydrate effect is a deliberate signal-write-in- effect: the URL is an external system and state is a caller-owned signal the consumer must stay able to toggle, so hydrate cannot be a computed. It is edge-guarded by serialized equality and wrapped in untracked().

Signature#

injectQueryParamSync(state: WritableSignal, opts: QueryParamSyncOptions)

Parameters#

Returns#

void