Validador angular 4 para verificar 2 controles al mismo tiempo
angular-reactive-forms angular-validation (2)
Tengo una forma reactiva con 2 controles (port_start y port_end) que tienen los siguientes requisitos:
- Ambos deben tener un valor
- Sus valores deben estar entre 0 y 65535
- el valor de port_start debe ser menor que el valor de port_end
Esto es lo que intenté hasta ahora:
[...]
this.formModel.addControl(''port_start'',
new FormControl(object.port_start ? object.port_start : 0,
[Validators.required, Validators.min(0), Validators.max(65535), this.minMaxValidator(''port_start'', ''port_end'').bind(this)]));
this.formModel.addControl(''port_end'',
new FormControl(object.ort_end ? object.port_end : 0,
[Validators.required, Validators.min(0), Validators.max(65535), this.minMaxValidator(''port_start'', ''port_end'').bind(this)]));
[...]
Esta es la función de validación personalizada:
minMaxValidator = function(startControl : string, endControl : string): ValidatorFn {
return (control: FormControl): {[key: string]: any} => {
let valid = true;
let valStart = 0;
let valEnd = 0;
if(this.formModel.controls[startControl] && this.formModel.controls[endControl]) {
valStart = <number>this.formModel.controls[startControl].value;
valEnd = <number>this.formModel.controls[endControl].value;
}
valid = valEnd >= valStart;
return valid ? null : { minmax : true };
};
}
Esto funciona bien, excepto por este problema:
- Digamos que escribo ''2'' en el campo ''port_start''. Angular lo marca como no válido porque es más que el valor de ''port_end'' (que es 0 por defecto). Si escribo ''5'' en el campo ''port_end'', la aplicación aún muestra ''port_start'' como no válido, aunque ahora es correcto.
Entiendo que el problema es que necesito volver a verificar el campo asociado cada vez que cambio el valor del otro, pero no sé cómo hacerlo.
¿Algunas ideas? Gracias,
A diferencia de @Tomasz dijo, puede mantener la validación en el nivel de control.
El secreto: escuche los cambios en su formulario y, cuando ocurra, configure los validadores con los valores actuales.
Aquí hay un stackblitz que te muestra cómo funciona.
Y aquí está el código que usé:
import { Component } from ''@angular/core'';
import { FormBuilder, FormGroup, ValidatorFn, AbstractControl } from ''@angular/forms'';
@Component({
selector: ''my-app'',
template: `
<form [formGroup]="form">
<input type="number" formControlName="start">
<input type="number" formControlName="end">
</form>
<div *ngIf="form.get(''start'').hasError(''lessThan'')">Min should be less than max</div>
<div *ngIf="form.get(''end'').hasError(''moreThan'')">Max should be less than min</div>
`,
styleUrls: [''./app.component.css'']
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = fb.group({
start: [0],
end: [65535]
});
this.form.valueChanges.subscribe(changes => {
this.form.get(''start'').setValidators(LessThanEnd(+this.form.value.end));
this.form.get(''end'').setValidators(MoreThanStart(+this.form.value.start));
});
}
}
export function LessThanEnd(end: number): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
return control.value > end ? { ''lessThan'': true } : null;
};
}
export function MoreThanStart(end: number): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
return control.value < end ? { ''moreThan'': true } : null;
};
}
Los validadores
max
,
max
y
required
pueden mantenerse tal cual.
Si desea validar un control en función del valor de otro, debe elevar la validación al control principal.
import { Component } from ''@angular/core'';
import { ValidatorFn, FormBuilder, FormGroup, Validators } from ''@angular/forms'';
const portStartEnd: ValidatorFn = (fg: FormGroup) => {
const start = fg.get(''portStart'').value;
const end = fg.get(''portEnd'').value;
return start && end && start < end ? null : { startEnd: true };
}
@Component({
selector: ''my-app'',
template: `
<input [formControl]="form.get(''portStart'')" type="number" >
<input [formControl]="form.get(''portEnd'')" type="number" >
{{ form.valid }}
`,
styleUrls: [''./app.component.css'']
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
portStart: [null, [Validators.required, Validators.min(0), Validators.max(65535)]],
portEnd: [null, [Validators.required, Validators.min(0), Validators.max(65535)]]
}, { validator: portStartEnd } );
}
}