QueryParams
Reactive wrapper around Angular Router's query parameters. Optionally validate parameters at runtime using schema validators for type checking, type coercion, and error handling.
Usage
Basic usage
import { Component } from '@angular/core';
import { queryParams } from '@signality/core';
@Component({
template: `
<p>Search: {{ queryParams().q }}</p>
<p>Sort: {{ queryParams().sort }}</p>
`,
})
export class SearchPage {
readonly queryParams = queryParams<{ q: string; sort: string }>();
}With schema validation
import { Component } from '@angular/core';
import { queryParams } from '@signality/core';
import { z } from 'zod';
const schema = z.object({
q: z.string().optional(),
page: z.coerce.number().default(1),
});
@Component({
template: `
<p>Search: {{ params.value().q }}</p>
<p>Page: {{ params.value().page }}</p>
`,
})
export class SearchPage {
readonly params = queryParams({ schema });
}Parameters
| Parameter | Type | Description |
|---|---|---|
options | QueryParamsOptions<T> | QueryParamsWithSchemaOptions<T> | Optional configuration (see Options below). When schema is provided, enables validation and returns QueryParamsRef<T>. |
Options
The options object extends CreateSignalOptions<T> and WithInjector:
| Option | Type | Default | Description |
|---|---|---|---|
equal | ValueEqualityFn<T> | - | Custom equality function (see more) |
debugName | string | - | Debug name for the signal (development only) |
schema | QueryParamsValidator<T> | - | Optional. Validator schema for runtime validation. When provided, returns QueryParamsRef<T> instead of Signal<T>. See Schema validation for details. |
injector | Injector | - | Optional injector for DI context |
Return Value
The return type depends on whether a schema is provided:
Without schema
Returns Signal<T> containing the current query parameters, where T is an object with string keys and values of any type (defaults to Record<string, any>).
With schema
Returns QueryParamsRef<T> — an object with the following properties:
| Property | Type | Description |
|---|---|---|
value | Signal<T> | Signal containing validated and transformed query parameters. Reading this signal throws an error if validation failed. Use isValid() to check before reading. |
isValid | Signal<boolean> | Signal indicating whether the current query parameters are valid according to the schema. true when valid, false when validation fails. |
error | Signal<unknown | null> | Signal containing the validation error object, or null if the parameters are valid. |
Examples
Accessing individual query params
import { Component, computed } from '@angular/core';
import { queryParams } from '@signality/core';
@Component({ /* ... */ })
export class SearchResults {
readonly queryParams = queryParams<{ q?: string; page?: string }>();
readonly search = computed(() => this.queryParams().q ?? '');
readonly page = computed(() => Number(this.queryParams().page ?? '1'));
}Schema validation
Validate query parameters at runtime using schema validators like Zod. When a schema is provided, queryParams returns a QueryParamsRef object with validation status and error information.
Reading value() in error state
Reading the value() signal on a QueryParamsRef that is in an error state throws at runtime. It is recommended to guard value() reads with isValid().
if (params.isValid()) {
// Safe to read params.value()
const data = params.value();
}import { Component, effect, signal } from '@angular/core';
import { queryParams } from '@signality/core';
import { z } from 'zod';
const searchSchema = z.object({
q: z.string().min(1).optional(),
page: z.coerce.number().int().positive().default(1),
});
@Component({ /* ... */ })
export class SearchPage {
readonly params = queryParams({ schema: searchSchema });
constructor() {
effect(() => {
if (this.params.isValid()) {
const { q, page } = this.params.value();
this.searchProducts(q, page);
}
});
}
async searchProducts(q?: string, page = 1) {
// API call implementation
}
}Custom validators
You can use any validator that implements the QueryParamsValidator interface:
interface QueryParamsValidator<T> {
parse(data: unknown): T;
}const pageSchema = {
parse(data: unknown): { page: string } {
const params = data as { page?: string };
const page = Number(params.page);
if (isNaN(page) || page < 1) {
throw new Error('Page must be a positive number');
}
return { page };
},
};SSR Compatibility
On the server, the signal initializes with the query params from the snapshot.
Type Definitions
interface QueryParamsValidator<T> {
parse(data: unknown): T;
}
interface QueryParamsRef<T> {
readonly value: Signal<T>;
readonly isValid: Signal<boolean>;
readonly error: Signal<unknown | null>;
}
type QueryParamsOptions<T extends Record<string, any> = Record<string, any>> = CreateSignalOptions<T> & WithInjector;
type QueryParamsWithSchemaOptions<T extends Record<string, any> = Record<string, any>> = QueryParamsOptions<T> & {
readonly schema: QueryParamsValidator<T>;
};
// Without schema - returns Signal<T>
function queryParams<T extends Record<string, any> = Record<string, any>>(options?: QueryParamsOptions<T>): Signal<T>;
// With schema - returns QueryParamsRef<T>
function queryParams<T extends Record<string, any> = Record<string, any>>(
options: QueryParamsWithSchemaOptions<T>
): QueryParamsRef<T>;