Reputation: 39364
Using Angular 12 I have a simple example form with Client and Server Validation.
I want to show Client Validation errors only after first Form submission;
I will show Server Validation errors after Client Validation is succeeded.
Server Validation errors are added as 'incorrect' field in Form Field errors.
I am using Reactive Forms.
The form is working as expected but I'm not sure if my implementation is the best option.
Component's HTML
<form [formGroup]="form">
<label for="email">Email</label>
<input id="email" type="text" formControlName="email">
<span class="error" *ngIf="form.get('email')?.invalid && form.get('email')?.touched">
{{form.get('email')?.errors?.incorrect}}
<ng-container *ngIf="form.get('email')?.errors?.required">Email required</ng-container>
<ng-container *ngIf="form.get('email')?.errors?.email">Invalid email</ng-container>
</span>
<button type="submit" (click)="send()" [disabled]="submitted">Send</button>
</form>
Component's Typescript
export class Component implements OnInit {
form: FormGroup;
submitted: boolean;
constructor(private service: Service) {
this.form = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
});
this.submitted = false;
}
send() {
this.submitted = true;
this.form.markAllAsTouched();
if (this.form.valid) {
this.service.send({email: this.form.value.email}).subscribe(
(next: Payload<Response>) => {
console.log("SUCCESS");
},
(error) => {
if (error.status === 400)
new FormGroupErrorBuilder(this.form).setErrors(error.errors);
this.submitted = false;
}
);
} else {
this.submitted = false;
}
}
}
FormGroupErrorBuilder
This is how I am adding server errors to Angular's FormGroup:
export class FormGroupErrorBuilder {
formGroup: FormGroup;
constructor(formGroup: FormGroup) {
this.formGroup = formGroup;
}
setErrors(errors: Error[]) {
for (let error of errors) {
var control = this.formGroup.get(error.name);
if (control)
control.setErrors({ incorrect: error.message });
}
}
}
Questions
Is it acceptable to use this.form.markAllAsTouched();
to fire validation for all form fields on first submit?
Using the condition *ngIf="form.get('email')?.invalid && form.get('email')?.touched"
a good option to show the form field errors?
Any suggestion to improve the code is welcome ...
Note:
I am using submitted
variable to control if the submit button is disabled or not and to change its CSS styles.
Upvotes: 0
Views: 804
Reputation: 57919
Take a look to Async custom validators in the docs:
If you create your formGroup with the option {updateOption:'submit'} I think you can achieve in other way
some like: e.g. (I put the validator in the FormGroup, you can put it in the own control Email) -then you should change the "validateEmail" function.
this.form = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
},{updateOption:'submit',asyncValidator:this.validateEmail()});
validateEmail(): AsyncValidatorFn {
return (group: FormGroup): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
return
this.service.send({email:group.value.email}).map(res=>{
if (res.success)
return null
return { repeat: "name yet register" }
})
)))
};
}
NOTE: I don't see clear in your code, when you subscribe to the service. You "catch" the error, Generally an API return some like {success:true}
or {error:'the email is yet!'}
, but don't return a status 400 if ther'e not an error in the call -your API can response some like above but you received the response in success, not in error.
Upvotes: 0