I am using Angular 11 reactive form with below 7 fields.
- Start Date (Mandatory)
- End Date (Mandatory)
At least one field is filled
- phone Number
- address
- author
- user ID
- company
My form should be valid only if start and end date are selected and among other five fields, at least one field is filled. How can I put this custom validator in my reactive form? Below is my typescript form component.
this.myForm = new FormGroup({
startDate: new FormControl('', Validators.required),
endDate: new FormControl('', Validators.required),
phoneNumber: new FormControl(''),
address: new FormControl(''),
author: new FormControl(),
userID: new FormControl(''),
company: new FormControl('')
}, { validators: dateValidator }
);
CodePudding user response:
Here's a basic example of how you're custom validator might look like:
export const atLeastOneValidator = (keys: string[]) => {
return (group: FormGroup) => {
const { controls } = group;
return keys.some(key => controls[key] && !!controls[key].value)
? null
: { atLeastOne: 'error' };
};
};
And here's how you could use it:
this.myForm = new FormGroup(
{
startDate: new FormControl('', Validators.required),
endDate: new FormControl('', Validators.required),
phoneNumber: new FormControl(''),
address: new FormControl(''),
author: new FormControl(),
userID: new FormControl(''),
company: new FormControl('')
},
{ validators: dateValidator, atLeastOneValidator(['phoneNumber', 'address', 'author', 'userID', 'company']) }
);
CodePudding user response:
You need 1 of them to exist. Not both of them. So remove Validators.required
that you have on both of them
this.myForm = new FormGroup({
startDate: new FormControl(''),
endDate: new FormControl(''),
phoneNumber: new FormControl(''),
address: new FormControl(''),
author: new FormControl(),
userID: new FormControl(''),
company: new FormControl('')
});
Then add a customValidator to the form
this.myForm.setValidators(this.atLeastOneFieldValidator())
Then create this validator
public atLeastOneFieldValidator() : ValidatorFn{
return (group: FormGroup): ValidationErrors => {
const startDate = group.controls['startDate'];
const endDate = group.controls['endDate'];
if (!startDate.value && !endDate.value) {
startDate.setErrors({atLeastOneError: "startDate or endDate must be filled"});
} else {
startDate.setErrors(null);
}
return;
};
}
Then in your html let this error show when exists only when 1 of those 2 fields has been modified. Not in the start state.
<div>
<form [formGroup]="myForm">
......
<div *ngIf="( myForm.controls['startDate'].dirty || myForm.controls['startDate'].touched || myForm.controls['endDate'].dirty || myForm.controls['endDate'].touched ) && myForm.controls['startDate'].errors?.atLeastOneError>
{{myForm.controls['startDate'].errors.atLeastOneError}}
</form>
</div>
CodePudding user response:
I have used the below code to solve the problem.
this.myForm = new FormGroup(
{
startDate: new FormControl('', Validators.required),
endDate: new FormControl('', Validators.required),
phoneNumber: new FormControl(''),
address: new FormControl(''),
author: new FormControl(),
userID: new FormControl(''),
company: new FormControl('')
},
{ validators: [dateValidator, atLeastOneValidator] }
);
Validator function :
export const atLeastOneValidator :ValidatorFn=(control: AbstractControl): ValidationErrors | null => {
if((control.get('phoneNumber')?.value!='')||(control.get('address')?.value!='')
||(control.get('author')?.value!='')||(control.get('userID')?.value!='')
||(control.get('company')?.value!='')){
return null;
}
else{
return {atLeastone : 'error'};
}
};