J'ai une forme réactive avec 2 contrôles (port_start et port_end) qui ont les exigences suivantes:
Voici ce que j'ai essayé jusqu'à présent:
[...]
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)]));
[...]
Voici la fonction de validation personnalisée:
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 };
};
}
Cela fonctionne bien, sauf pour ce problème:
Je comprends que le problème est que je dois revérifier le champ associé chaque fois que je change la valeur de l'autre, mais je ne sais pas comment le faire.
Des idées? Merci,
Les validateurs min
, max
et required
peuvent être conservés tels quels. Si vous souhaitez valider un contrôle en fonction de la valeur d'un autre, vous devez lever la validation vers le contrôle parent.
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 } );
}
}
Contrairement à @Tomasz, vous pouvez conserver la validation au niveau du contrôle.
Le secret: écoutez les changements sur votre formulaire, et quand cela se produit, définissez les validateurs avec les valeurs actuelles.
Voici un stackblitz qui vous montre comment cela fonctionne.
Et voici le code que j'ai utilisé:
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;
};
}