Inicio › Aprender
Formularios
Enlazar campos con ngModel y formularios reactivos con validadores sobre señales.
Enlazar campos con ngModel#
[(ngModel)]="señal" conecta un campo con una señal escribible: lo que escribe el usuario actualiza la señal, y si cambias la señal, el campo se actualiza. Sirve para input (texto, número, casilla) y select. Para formularios con validación, usa los formularios reactivos de abajo.
Ver el código
const { signal, computed, component, mount } = AngeLite;
class Greeter {
name = signal('mundo');
price = signal(1234.5);
today = new Date();
}
component(Greeter, {
template: `
<input [(ngModel)]="name">
<p>Hola, {{ name() | titlecase }}! ({{ name() | uppercase }})</p>
<p>Precio: {{ price() | currency:'EUR' }} · Hoy: {{ today | date }}</p>`
});
mount(Greeter, root);[(ngModel)] con un computed o con un valor que no sea una señal lanza un error claro («needs a writable signal»).
Formularios reactivos#
FormControl, FormGroup y FormArray (@duvanjamid/angelite/forms) guardan su estado en señales: value, errors, valid, touched y dirty. Como value es una señal escribible, se enlaza con [(ngModel)], y como el resto son señales, la plantilla reacciona sola.
Un validador es una función (valor) => null | { clave: detalle }. Vienen required, minLength, maxLength, min, max, pattern, email y matches (para «repite la contraseña»). Los errores de varios validadores se fusionan en errors().
Ver el código
const { signal, component, mount, FormControl, FormGroup, Validators: V } = AngeLite;
class Registro {
form = new FormGroup({
nombre: new FormControl('', [V.required, V.minLength(2)]),
email: new FormControl('', [V.required, V.email])
});
enviado = signal('');
enviar() {
this.form.touch(); // marca todo como tocado para mostrar errores
if (this.form.valid()) this.enviado.set('Enviado: ' + JSON.stringify(this.form.value()));
}
}
component(Registro, {
template: `
<p><input [(ngModel)]="form.get('nombre').value" (blur)="form.get('nombre').touch()" placeholder="Nombre">
@if (form.get('nombre').touched() && form.get('nombre').errors()) {<span class="err">mínimo 2 letras</span>}</p>
<p><input [(ngModel)]="form.get('email').value" (blur)="form.get('email').touch()" placeholder="Email">
@if (form.get('email').touched() && form.get('email').errors()) {<span class="err">email no válido</span>}</p>
<button (click)="enviar()" [disabled]="!form.valid()">Enviar</button>
<p>{{ enviado() }}</p>`
});
mount(Registro, root);| Quieres… | Usa |
|---|---|
| Mostrar un error solo después de que el usuario toque el campo | (blur)="campo.touch()" y campo.touched() && campo.errors() |
| Mostrar todos los errores al enviar | form.touch() marca todo como tocado |
| Campos anidados | new FormGroup({ direccion: new FormGroup({ calle: … }) }) y form.get('direccion.calle') |
| Listas de campos que crecen | FormArray con push() y removeAt(); @for (c of lista.controls(); track $index) |
| Volver al estado inicial | form.reset() o form.reset({ nombre: 'x' }) |
| Una regla que mira varios campos | un validador en el grupo: new FormGroup(controles, [v => …]) |
Todavía no hay validadores asíncronos. Para «¿ese correo ya existe?», valida al enviar con http y pon el error a mano en tu propio estado.