Angelitedocs ESEN

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.

ngModel + pipesen vivo
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);
La señal tiene que ser escribible

[(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().

FormGroup con validadoresen vivo
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 enviarform.touch() marca todo como tocado
Campos anidadosnew FormGroup({ direccion: new FormGroup({ calle: … }) }) y form.get('direccion.calle')
Listas de campos que crecenFormArray con push() y removeAt(); @for (c of lista.controls(); track $index)
Volver al estado inicialform.reset() o form.reset({ nombre: 'x' })
Una regla que mira varios camposun validador en el grupo: new FormGroup(controles, [v => …])
Qué falta

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.