I'm looking at adding some basic email validation to check that the user has put in a correct email address. Currently using the method below, the validation updates as the user types, which looks odd when it errors after entering one character.
validEmail(c: Control){ if(!c.value.match('[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')){ return { validEmail: true }; } return null; } ctrlEmailAddress: Control = new Control('', Validators.compose([ Validators.required, this.validEmail]));
I was wondering if it is possible to trigger the validation on blur of the field, like in angularJS with:
ng-model-options="{ updateOn: 'blur' }"
I'm aware of the blur option on the input field within the html but this doesn't put my control in error unless there is a way to put the control into an error state.
Could anyone help point me in the right direction?
Thanks.
Edit: I'm looking for a angular2 solution, not an angularJS solution.
To add validation to a template-driven form, you add the same validation attributes as you would with native HTML form validation. Angular uses directives to match these attributes with validator functions in the framework.
We use updateOn: 'submit' on the FormGroup level and updateOn: 'blur' on the fullName FormControl . With this, the fullName control will update only when the corresponding input loses focus. For the email control, the updates only happen when the parent form is submitted.
Inside the root. component. html file, add the ngIf directive to show the message when the form is submitted and the required validator is true. Save the changes and run the app.
EDIT 2
As Alex and the official documentation says, Angular version 5.0.0 has new option for your ngModel updateOn: 'blur'
this.email = new FormControl(null, { validators: Validators.required, updateOn: 'blur' });
Also you can use other update options: change
(default), blur
, submit
.
Original
I use directive where remove whole validation on focus and return it back after blur event. It based on Cristian Deschamps answer.
I update validity only on blur, so if value was invalid before focus it will be invalid after. But if you start input, validity will be updated.
For some reasons clearing order make sense, so I clear async validators first.
Any provided suggestion will be helpful =)
import { Directive } from '@angular/core'; import { NgControl } from '@angular/forms'; @Directive({ selector: '[validate-onblur]', host: { '(focus)': 'onFocus($event)', '(blur)': 'onBlur($event)' } }) export class ValidateOnBlurDirective { private validators: any; private asyncValidators: any; constructor(public formControl: NgControl) { } onFocus($event) { this.validators = this.formControl.control.validator; this.asyncValidators = this.formControl.control.asyncValidator; this.formControl.control.clearAsyncValidators(); this.formControl.control.clearValidators(); } onBlur($event) { this.formControl.control.setAsyncValidators(this.asyncValidators); this.formControl.control.setValidators(this.validators); this.formControl.control.updateValueAndValidity(); } }
Also, please stay tuned on this Angular 2 github thread about onBlur validation
EDIT 1
There is another problem - if I just click on the field and after click away - validation will be called. If you have any notification about it (or server calls) - it would appear every time you do it. So you can add wasChanged
property and use it like this:
@Directive({ selector: '[validate-onblur]', host: { '(focus)': 'onFocus($event)', '(blur)': 'onBlur($event)', '(keyup)': 'onKeyup($event)', '(change)': 'onChange($event)', '(ngModelChange)': 'onNgModelChange($event)' } }) export class ValidationOnBlurDirective { private validators: any; private asyncValidators: any; private wasChanged: any; constructor(public formControl: NgControl) { } onFocus($event) { this.wasChanged = false; this.validators = this.formControl.control.validator; this.asyncValidators = this.formControl.control.asyncValidator; this.formControl.control.clearAsyncValidators(); this.formControl.control.clearValidators(); } onKeyup($event) { this.wasChanged = true; // keyboard change } onChange($event) { this.wasChanged = true; // copypaste change } onNgModelChange($event) { this.wasChanged = true; // ng-value change } onBlur($event) { this.formControl.control.setAsyncValidators(this.asyncValidators); this.formControl.control.setValidators(this.validators); if (this.wasChanged) this.formControl.control.updateValueAndValidity(); } }
As of Angular v 5.0.0
this is now possible by marking updateOn: 'blur'
to the form control.
This also means that valueChanges
does not fire for that form control until the blur event occurs. Here's an example wiht minlength
together with required
:
this.form = new FormGroup({ username: new FormControl('', { validators: [Validators.required, Validators.minLength(6)], updateOn: 'blur'} ) }) get username() { return this.form.get('username'); }
In the template you'd want to mark that the validation message won't show unless the field is touched
:
<div *ngIf="username.hasError('minlength') || username.hasError('required') && username.touched">Required and minlength 6! </div>
DEMO
P.S If needed you can also mark this on the whole form, not only on a specific form control
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With