- Formularios reactivos
- Diseño de formulario en la vista
- Mostrando el estado del formulario
- Mensajes de error personalizados
- Modelo
- Campos obligatorios
- Botón para procesar el formulario
- Suscripción en cambios de estado y valor
- Apellido obligatorio
- Añadiendo nuevas restricciones
- Código fuente del proyecto
- Enlaces externos
[Fuente]
Los formularios reactivos en Angular también se conocen como formularios dirigidos por modelos, los formularios se diseñan en el componente (usando FormBuilder
y el método group
) y luego se realizan los enlaces para el HTML usando la inyección de dependencias en el constructor.
Formularios reactivos
Antes de empezar hay que añadir en [src/app/app.module.ts] la importación del módulo ReactiveFormsModule
:
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { ReactiveFormsModule } from "@angular/forms"; // <---
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, ReactiveFormsModule], // <----
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Diseño de formulario en la vista
La clase FormGroup
agrupa los controles FormControl
de un formulario en un objeto, angForm
es un atributo de la clase AppComponent
, cuando se instancia la clase FormGroup
podemos pasar como argumento una colección de controles hijo.
<div style="text-align:center">
<h1>Welcome to {{ title }}!!</h1>
<form [formGroup]="angForm" novalidate>
<div class="form-group">
<label class="center-block"
>Name:
<input class="form-control" formControlName="name" />
</label>
</div>
<div
*ngIf="
angForm.controls['name'].invalid &&
(angForm.controls['name'].dirty || angForm.controls['name'].touched)
"
class="alert alert-danger"
>
<div *ngIf="angForm.controls['name'].errors.required">
Name is required.
</div>
</div>
</form>
<p>Form value: {{ angForm.value | json }}</p>
<p>Form status: {{ angForm.status | json }}</p>
</div>
Mostrando el estado del formulario
El estado inicial es no valido. El estado global del formulario es accesible a través del atributo status de tipo string de la clase FormGroup
. Usando la técnica de bata binding por interpolación del modelo a la vista se muestra en todo momento el estado del formulario.
<p>Form status: {{ angForm.status | json }}</p>
Mensajes de error personalizados
Condicionamos que se muestre este mensaje de error con una condicional ngIf
accediendo al control que queremos comprobar:
<div *ngIf="angForm.controls['name'].errors.required">
Name is required.
</div>
Modelo
[src/app/app.component.ts]
import { Component } from "@angular/core";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
title = "Angular Form Validation Tutorial";
angForm: FormGroup;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.angForm = this.fb.group({
name: ["", Validators.required]
});
}
} // FIN class
Como atributo de la clase se declara angForm
que es una instancia de la clase FormGroup
.
El servicio FormBuilder
se inyecta en el constructor de la clase, el constructor llama a un método interno createForm
.
Campos obligatorios
El control más habitual en los controles de un formulario es que los datos a introducir sean obligatorios. FormBuilder
tiene el método group
(azucarillo sintáctico) para facilitar la creación de instancias FormControl
, como parámetro de le pasa una colección con los controles hijo.
La clase Validators
que hemos importado en la cabecera tiene ya métodos para las validaciones más típicas: min
, max
, email
, maxLength
, required
, etc.
Nota: En HTML5 existe el atributo required
para el mismo propósito:
<input class="form-control" formControlName="name" required />
Botón para procesar el formulario
Aún falta el típico botón de submit, modifico la etiqueta form de la vista.
La directiva FormGroup
escucha el evento submit
emitido por el elemento form
y emite un evento ngSubmit
que asociamos a una función de callback.
Añadimos el capturador de evento en la etiqueta form:
<form [formGroup]="angForm" (ngSubmit)="onSubmit()" novalidate>
onSubmit() {
if (this.angForm.valid) {
console.log(this.angForm.value);
} else {
alert("FILL ALL FIELDS");
}
}
Suscripción en cambios de estado y valor
Las clases FormControl
, FormGroup
, y FormArray
definen un observable al que podemos suscribirnos para controlar cualquier cambio de estado.
En el método createForm()
añadimos la siguiente línea:
this.angForm.controls["name"].valueChanges.subscribe(data => {
console.log(data);
});
Apellido obligatorio
Añadir nuevos campos es trivial, solo tenemos que definirlos en la vista:
<input class="form-control" formControlName="surname" />
Y en el método createForm()
:
this.angForm = this.fb.group({
name: ["", Validators.required],
surname: ["", Validators.required]
});
Añadiendo nuevas restricciones
Voy a controlar la longitud máximo del nombre, debe ser como mucho de longitud 5.
createForm() {
this.angForm = this.fb.group({
name: ["", [Validators.required, Validators.maxLength(5)]],
surname: ["", Validators.required]
});
}
Código fuente del proyecto
- En mi repositorio GitLab: angular / src / ui / forms / ngValidation.
En StackBlitz:
Enlaces externos
- "Reactive Forms": Toda la información paso a paso en la documentación oficial de Angular.
- Class "Validators.
- "FormGroup - Angular".
- "Angular Form Validation Example Tutorial!".
- "Angular 7 - Formularios (Template y Reactive) | JoLuGaMa Blog".
- jasonwatmore.com "Angular 7 - Reactive Forms Validation Example".