Sergio Hidalgo
Apasionado por la tecnología. Ninja Developer, FullStack, Adm Servidores, Profesor de Angular, Node, Phaser, Javascript. sergiohidalgocaceres@gmail.com https://www.facebook.com/groups/607163139705114/
Formularios
ReactiveFormsModule
FormsModule
La validación se hace en el DOM
La validación se hace en el TypeScript
FormsModule
Para usar FormsModule primero hay que importarlo y declararlo en un módulo.
El FormsModule pertenece a "@angular/forms".
<!-- app.module.ts -->
import { FormsModule } from "@angular/forms"
@NgModule({
...
imports: [FormsModule],
...
})Los campos (inputs, textareas, selects, etc.) se deben vincular a "ngModel" y tener seteada la propiedad "name"
<input type="text" name="nombre" ngModel>Los formularios se vinculan a través de referencias locales.
<form #f>
...
</form>Pero una mejor forma es hacer que la referencia local herede de la clase "NgForm"
<form #f="ngForm">
...
</form>El envío de los datos ingresados en los campos se hará a través del evento "ngSubmit".
<form #f="ngForm" (ngSubmit)="grabar()">
...
</form>Con FormsModule, los validadores se aplican directamente al DOM.
<input type="text" name="nombre" ngModel required>
<input type="email" name="correo" ngModel required email>
<input type="tel" name="telefono" ngModel required min(7) max(9)>El formulario completo se puede validar a través de la propiedad "valid".
<form #f="ngForm" (ngSubmit)="grabar()">
...
<button [disabled]="!f.valid">Grabar</button>
</form>Cuando un campo no es válido, Angular le agrega algunas clases. Las que necesitaremos son "ng-invalid" y "ng-touched".
<form ...>
...
<input class="ng-invalid ng-touched" ...>
</form>Podemos crear una regla de estilos para resaltar el campo no válido.
input.ng-invalid.ng-touched {
border: 1px solid red
}No solo se puede validar el formulario completo. También podemos validar cada campo a través de una referencia local.
<form ...>
...
<input ... #campo="ngModel">
</form>También podemos manejar los mensajes de error de cada campo.
<form ...>
...
<input ... #campo="ngModel">
<span *ngIf="!campo.valid && campo.touched">
Campo no válido
</span>
</form>Puede haber comunicación bi-direccional a través de "ngModel".
<form ...>
...
<input ... [(ngModel)]="propiedad">
</form>Se pueden crear grupos de validación a través de "ngModelGroup".
<form ...>
<div ngModelGroup="dataUsuario"
#dataUsuario="ngModelGroup">
<input type="text" name="nombre" ngModel>
</div>
<span *ngIf="!dataUsuario.valid && dataUsuario.touched">
El formulario no es válido
</span>
</form>Validación de radiobuttons.
<!-- app.component.ts -->
...
export class AppComponent {
generos: string[] = ["hombre", "mujer"]
...
}<!-- app.component.html -->
...
<label *ngFor="let genero of generos">
<input type="radio" name="genero"
ngModel [value]="genero" required>
{{genero}}
</label>Uso de "setValue"
<!-- app.component.ts -->
...
export class AppComponent {
@ViewChild("f") registro: NgForm
ngOnInit(){
this.registro.setValue({
"nombre": "Nombre Persona",
"apellido": "Apellido Persona"
})
}
}Uso de "patchValue"
<!-- app.component.ts -->
...
export class AppComponent {
@ViewChild("f") registro: NgForm
ngOnInit(){
this.registro.form.patchValue({
"nombre": "Nombre Persona"
})
}
}Uso de "reset"
<!-- app.component.ts -->
...
export class AppComponent {
@ViewChild("f") registro: NgForm
grabar(){
...
this.registro.reset({
"nombre": "Nombre Persona",
"apellido": "Apellido Persona"
})
}
}Tarea 1
- Crear un formulario de registro con los siguientes campos:
nombre completo, género, correo y contraseña.
- El nombre completo es requerido y no puede estar en blanco.
- El usuario seleccionará género a través de un select.
- El correo es requerido, debe ser un correo y no debe estar en blanco. Mostrar mensajes de error diferentes dependiendo del error.
- Debe haber un botón de envío el cual no enviará nada a menos que el formulario sea válido. Si lo es, imprimirá en consola todos los campos.
ReactiveFormsModule
Para usar ReactiveFormsModule primero hay que importarlo y declararlo en un módulo.
El ReactiveFormsModule pertenece a "@angular/forms".
<!-- app.module.ts -->
import { ReactiveFormsModule } from "@angular/forms"
@NgModule({
...
imports: [ReactiveFormsModule],
...
})Con ReactiveFormsModule se usan FormGroup y FormControl.
<!-- app.component.ts -->
...
export class AppComponent {
...
grupo: FormGroup
ngOnInit(){
this.grupo = new FormGroup({
"nombre": new FormControl(null, Validators.required),
"apellido": new FormControl("Apellido Persona",
Validators.required),
"correo": new FormControl("Correo Persona",
[Validators.required, Validators.email])
})
}
}Con ReactiveFormsModule se usan FormGroup y FormControl.
<!-- app.component.html -->
...
<form [formGroup]="grupo">
<input type="text" formControlName="nombre">
<input type="text" formControlName="apellido">
<button [disabled]="!grupo.valid">Grabar</button>
</form>
...Para validar se usa "Validators" el cual forma parte de "@angular/forms"
import { Validators } from "@angular/forms" Para manejar mensajes de error se usa el método "get".
<!-- app.component.html -->
...
<form [formGroup]="grupo">
<input type="text" formControlName="nombre">
<span
*ngIf="!grupo.get('nombre').valid
&& grupo.get('nombre').touched">
Error
</span>
<input type="text" formControlName="apellido">
<button [disabled]="!grupo.valid">Grabar</button>
</form>
...Tarea 2
- Lo mismo que la tarea 1 pero usando ReactiveFormsModule.
Creación de validador
Supongamos que tenemos el siguiente formulario y necesitamos que el correo sea ingresado y además tenga formato de correo.
<form [formGroup]="grupo">
<input type="email" formControlName="correo">
<button (click)="grabar()">Grabar</button>
</form>En el TypeScript implementaremos el siguiente código.
grupo: FormGroup;
ngOnInit() {
this.grupo = new FormGroup({
correo: new FormControl(null, [
Validators.required,
Validators.email
])
});
}Supongamos que además se necesita que el correo no sea gratuito, es decir que no sea un correo de Gmail, Hotmail, Outlook o Yahoo.
grupo: FormGroup;
correosProhibidos: Array<string> = [
"gmail.com", "hotmail.com", "outlook.com", "yahoo.com"
];
ngOnInit() {
this.grupo = new FormGroup({
correo: new FormControl(null, [
Validators.required,
Validators.email
])
});
}Creemos un método llamado "excluirCorreos".
...
correosProhibidos: Array<string> = [
"gmail.com", "hotmail.com", "outlook.com", "yahoo.com"
];
...
excluirCorreos(form: FormControl): { [s: string]: boolean } {
if (form.value) {
const partes: string[] = form.value.split("@");
if (partes[1]) {
if (this.correosProhibidos.indexOf(partes[1].toLowerCase()) > -1) {
return { correoProhibido: true };
}
}
}
return null;
}Agregamos el método "excluirCorreos" como un validador.
grupo: FormGroup;
correosProhibidos: Array<string> = [
"gmail.com", "hotmail.com", "outlook.com", "yahoo.com"
];
ngOnInit() {
this.grupo = new FormGroup({
correo: new FormControl(null, [
Validators.required,
Validators.email,
this.excluirCorreos.bind(this)
])
});
}Supongamos que agregamos los campos "contraseña" y "confirmar contraseña"
<form [formGroup]="grupo">
<input type="email" formControlName="correo">
<input type="password" formControlName="contrasena">
<input type="password" formControlName="confirmarContrasena">
<button (click)="grabar()">Grabar</button>
</form>Creamos una función "confirmaContraseña".
function confirmarContrasena(control: AbstractControl) {
if (!control.parent || !control) {
return;
}
const contrasena = control.parent.get("contrasena");
const confirmarContrasena = control.parent.get("confirmarContrasena");
if (!contrasena || !confirmarContrasena) {
return;
}
if (confirmarContrasena.value === "") {
return;
}
if (contrasena.value !== confirmarContrasena.value) {
return {
contrasenasNoCoinciden: true
};
}
}Noten que para agregar el validador, ahora la implementación en el FormControl es un poco diferente.
ngOnInit() {
this.grupo = new FormGroup({
correo: new FormControl(null, [
Validators.required,
Validators.email,
this.excluirCorreos.bind(this)
]),
contrasena: new FormControl(null, Validators.required),
confirmarContrasena: new FormControl(null, [
Validators.required,
this.confirmarContrasena
])
});
}By Sergio Hidalgo
Fomularios: FormsModule vs ReactiveFormsModule, ¿cómo usarlos? ¿cómo validar?
Apasionado por la tecnología. Ninja Developer, FullStack, Adm Servidores, Profesor de Angular, Node, Phaser, Javascript. sergiohidalgocaceres@gmail.com https://www.facebook.com/groups/607163139705114/