Reputation: 852
I have two form fields, where if the first field is filled in, the second field is mandatory. If I try to do this in Angular2, using a custom validator, the validator is only fired on initialization and when the specific field is changed.
Case: - User fills in field 1 - Field 2 should become required, but isn't till the user actually changes field 2 (firing the custom validation).
private createForm():void {
this.testForm = this._formBuilder.group({
'field1': [],
'field2': ['', this.validateRequired()]
});
}
private validateRequired(){
console.log("something", this);
let component = this;
return (control: Control): { [s: string]: boolean } => {
return component.testModel.field1 && !control.value {"required":true} : null;
}
}
See this plunkr: http://plnkr.co/edit/PEY2QIegkqo8BW1UkQS5?p=preview
Edit:
For now I subscribed to field1's valueChange observable and when changed execute a manual check on field2, like:
this.testForm.controls['field1'].valueChanges.subscribe(
value => {
component.testForm.controls['field2].updateValueAndValidity();
}
)
But I feel like there must be a better way to do this.
Upvotes: 0
Views: 786
Reputation: 1158
I want to expand on Thierry's answer a bit in order to address Arne's comment. In order to handle the validation of multiple fields and possibly multiple validations in your formgroup level validator the solution is to return a function from your validator that then returns an object that indicates the error type. Here is a example of a field matching validator that I added some extra errors to in order to illustrate the point. Note that it returns an object with possibly several properties where each object property is any string and the value is a boolean.
export function FieldMatchingValidator(field1: string, field2 :string) {
return (cg: FormGroup): { [s: string]: boolean } => {
let retVal = null;
let f1 = cg.controls[field1];
let f2 = cg.controls[field2];
retVal = f1.value === f2.value ? null : { fieldMismatch: true };
if(somecondition){
retVal['someerror'] = true;
}
if(someothercondition){
retVal['someothererror'] = true;
}
return retVal;
}
}
When this validator runs, if an error condition is encountered, then the form's errors property will be populated with the returned object with one or more properties indicating different errors. Then all you have to do it put the appropriate angular property setting on the controls that have the validation errors.
<div *ngIf="myForm.hasError('fieldMismatch')">
Field Mismatch
</div>
<div *ngIf="myForm.hasError('someerror')">
Some Error
</div>
<div [class.Errors]="myForm.hasError('someothererror')">
Some Other Error
</div>
Upvotes: 0
Reputation: 202346
You could use a global validator for the group like this:
private createForm():void {
this.testForm = this._formBuilder.group({
'field1': [],
'field2': ['', this.validateRequired()]
}, {
validator: this.someGlobalValidator // <-----
});
}
someGlobalValidator(group: ControlGroup) { // <-----
var valid = false;
for (name in group.controls) {
var val = group.controls[name].value
(...)
}
if (valid) {
return null;
}
return {
someValidationError: true
};
}
Upvotes: 1