Completa los datos para registrarte.
{{ error }}
Subiendo…
{{ error }}
El formulario tiene errores
Hay cambios sin guardar
{{ form.values.value }}
```
## Acciones programáticas
[Sección titulada «Acciones programáticas»](#acciones-programáticas)
```js
// Setear un valor
form.setValue('email', 'foo@bar.com');
// Setear varios (merge, no replace)
form.setValues({ email: 'foo@bar.com', age: 30 });
// Marcar como touched (muestra errores)
form.touch('email');
form.touchAll();
// Forzar validación
const isOk = form.validate();
// Submit (corre validate + onSubmit)
await form.submit();
// Reset a initialValues + defaults del schema
form.reset();
// Reset a valores específicos
form.reset({ email: 'nuevo@ejemplo.com' });
```
## Schema reactivo
[Sección titulada «Schema reactivo»](#schema-reactivo)
Si el schema depende de props o state (ej. cambia según el rol del usuario), pasa un **getter**:
```vue
```
Cuando `props.role` cambie, `useForm` reconstruye el controller con el nuevo schema. Los valores existentes se preservan en la medida que sean compatibles con el nuevo schema.
## Initial values
[Sección titulada «Initial values»](#initial-values)
```js
const form = useForm(() => ({
schema: { modelSchema: userSchema, locale: 'es' },
initialValues: {
email: 'usuario@empresa.com',
role: 'admin',
newsletter: true,
},
}));
```
`initialValues` se mergea con los `default` del schema. Los valores explícitos siempre ganan sobre los defaults.
`isDirty` se calcula contra esta combinación (initialValues + defaults). Si haces `setValue` y luego vuelves al valor inicial, `isDirty` regresa a `false`.
## Submit
[Sección titulada «Submit»](#submit)
```vue
```
### Flujo interno del `submit()`
[Sección titulada «Flujo interno del submit()»](#flujo-interno-del-submit)
1. `touchAll()` — marca todos los campos como touched (para mostrar todos los errores)
2. `validate()` — re-valida con AJV
3. Si **inválido**: detiene el submit y deja `isSubmitting = false`
4. Si **válido**: setea `isSubmitting = true`, ejecuta `onSubmit(values)`, espera la promise
5. Al finalizar (éxito o error): `isSubmitting = false`
## Subscripción cruda al state
[Sección titulada «Subscripción cruda al state»](#subscripción-cruda-al-state)
Si necesitas un listener (ej. para logging, telemetría), usa `form.controller.value.subscribe`:
```js
const unsubscribe = form.controller.value.subscribe((state) => {
console.log('form state:', state);
});
onUnmounted(unsubscribe);
```
Patrón recomendado: form en composable propio
Para forms reutilizables (ej. el form de un User), envuelve `useForm` en tu propio composable:
composables/useUserForm.js
```js
export function useUserForm(initial = {}) {
return useForm(() => ({
schema: { modelSchema: userSchema, locale: 'es' },
initialValues: initial,
onSubmit: async (values) => api.saveUser(values),
}));
}
```
Así los consumidores solo hacen `const form = useUserForm(props.user)` y olvidan el schema.
# Validación
> Cómo funciona AJV, cuándo se valida, locales de error y validación custom.
La validación es **síncrona, schema-driven, traducida** — funciona out-of-the-box sin que escribas un solo validador.
## Motor: AJV 8
[Sección titulada «Motor: AJV 8»](#motor-ajv-8)
[AJV](https://ajv.js.org/) es el validador de JSON Schema más rápido y estricto en npm. Cobalt lo configura con:
* **`ajv-formats`** para `email`, `date`, `uri`, `uuid`, `regex`, etc.
* **`ajv-i18n`** para traducir mensajes de error al locale del usuario.
* **`allErrors: true`** para capturar TODOS los errores de un campo, no solo el primero.
## Cuándo se valida
[Sección titulada «Cuándo se valida»](#cuándo-se-valida)
Por defecto, la validación corre:
1. **En la construcción del form** — para que el state inicial refleje si el form es válido o no (útil para deshabilitar el submit desde el inicio).
2. **En cada `setValue()`** — validación en vivo mientras el usuario escribe.
3. **En `submit()`** — re-valida antes de emitir el evento. Si hay errores, marca todos los campos como `touched` para que el usuario vea todos los mensajes a la vez.
Puedes cambiar este comportamiento con la opción `validateOn`:
```js
const form = createForm({
schema: { modelSchema, locale: 'es' },
validateOn: 'blur', // 'change' | 'blur' | 'submit'
});
```
| Valor | Comportamiento |
| ---------------------- | ----------------------------------------------------------------------- |
| `'change'` *(default)* | Valida en cada `setValue`. UI en vivo. |
| `'blur'` | Valida solo cuando el campo pierde foco. Menos ruido para forms largos. |
| `'submit'` | Solo valida en `submit()`. Modo “old school”. |
## Errores
[Sección titulada «Errores»](#errores)
El state expone `errors` como `Record