# Page Params Guide

This guide explains how typed page params work in Zova within the Cabloy monorepo.

## Why page params support matters

Zova enhances route params handling with typed support so page controllers can work with route parameters through a structured schema instead of ad hoc string access.

## Add params support to a page

Example: add params support for page `counter`.

```bash
npm run zova :refactor:pageParams counter -- --module=training-student
```

## Add params schema

Representative pattern:

```typescript
export const ControllerPageCounterSchemaParams = z.object({
  id: z.number().optional().default(0),
});
```

This is more than a type annotation.

Route params arrive as strings at the URL level. On Zova's route/query parsing path, the Cabloy Zod query adapter converts a numeric value before the `z.number()` validation runs, so a successful `$params.id` value is a number. Use `z.number()` for numeric page params; `z.coerce.number()` is normally redundant here. For the exact scope and nil/error semantics, see [Zova route/query number parsing](./zod-guide#zova-routequery-number-parsing).

## Route record requirements

A page route that declares or consumes dynamic params **must** define `route.name`. Do not use an unnamed route with params.

The route name is required because Zova uses the named route identity to generate and resolve the page's typed `params` schema at runtime. This initializes the controller's `$params` surface during SSR and client navigation. A params schema declaration alone does not make `$params` available if the route is unnamed.

Conversely, a static route should not add a name merely for typing, canonical URL generation, or alias convenience. Use the path-keyed `$router.getPagePath(...)` helper for a known canonical static path; keep a static name only for a documented named-route requirement.

Representative route idea:

```typescript
{
  name: 'counter',
  path: 'counter/:id?',
  component: ZPageCounter,
}
```

## Regenerate metadata

When the route definition changes, regenerate module metadata so the framework’s typed route information stays aligned.

```bash
npm run zova :tools:metadata training-student
```

For the broader schema model behind `z`, coercion, defaults, and nested structures, see [Zod Guide](/frontend/zod-guide).

## Use params in a page

Representative pattern:

```typescript
class ControllerPageCounter {
  render() {
    return <div>{this.$params.id}</div>;
  }
}
```

## Pass params during navigation

Representative pattern:

```typescript
const url = this.$router.getPagePath('/training/student/counter/:id?', {
  params: {
    id: 1,
  },
});
this.$router.push(url);
```

## Implementation checks for param-driven page changes

When adding or editing param-driven page behavior:

1. use the Zova refactor command when possible
2. define `route.name` whenever the route has dynamic params
3. regenerate metadata when route typing depends on it
4. use `this.$params` and typed router helpers instead of manual parsing
