angular - updatevalueandvalidity - reactive form submit
Angular2-ValidaciĆ³n de FormControl en desenfoque (6)
Estoy buscando agregar una validación básica de correo electrónico para verificar que el usuario haya ingresado una dirección de correo electrónico correcta. Actualmente, utilizando el método siguiente, la validación se actualiza a medida que el usuario escribe, lo que parece extraño cuando se produce un error después de ingresar un carácter.
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]));
Me preguntaba si es posible activar la validación en el desenfoque del campo, como en angularJS con:
ng-model-options="{ updateOn: ''blur'' }"
Soy consciente de la opción de desenfoque en el campo de entrada dentro del html, pero esto no pone mi control en error a menos que haya una forma de poner el control en un estado de error.
¿Podría alguien ayudarme a señalarme en la dirección correcta?
Gracias.
Editar: estoy buscando una solución angular2, no una solución angularJS.
A partir de
Angular v
5.0.0
esto ahora es posible marcando
updateOn: ''blur''
en el control de formulario.
Esto también significa que
valueChanges
no se
valueChanges
para ese control de formulario hasta que se produce el evento de desenfoque.
Aquí hay un ejemplo con
minlength
junto con
required
:
this.form = new FormGroup({
username: new FormControl('''', {
validators: [Validators.required, Validators.minLength(6)], updateOn: ''blur''} )
})
get username() {
return this.form.get(''username'');
}
En la plantilla, desea marcar que el mensaje de validación no se mostrará a menos que se
touched
el campo:
<div *ngIf="username.hasError(''minlength'') || username.hasError(''required'')
&& username.touched">Required and minlength 6!
</div>
PD: si es necesario, también puede marcarlo en todo el formulario, no solo en un control de formulario específico
Algo como esto: Use la propiedad tocada del objeto ngControl .
<div class="form-group" [class.has-error]="!name.valid && name.touched">
<label for="name">Name</label>
<input #name="ngForm" ngControl="name" name="name" type="text" class="form-control" required>
</div>
Encontrado un camino, en rc6.
1- Crear una directiva: validate-onblur.directive.ts
@Directive({
selector: ''[validate-onblur]'',
host: {
''(focus)'': ''onFocus($event)'',
''(blur)'': ''onBlur($event)''
}
})
export class ValidateOnBlurDirective {
constructor(public formControl: NgControl) {
}
onFocus($event) {
this.formControl.control.markAsUntouched(false);
}
onBlur($event) {
this.formControl.control.markAsTouched(true);
}
}
Luego, en su plantilla html, simplemente agregue la directiva a su formulario, mi ejemplo usa el modelo ReactiveFormsModule.
Luego agregue esto a su mensaje de error:
<input type="text" formControlName="full_name" validate-onblur />
<span *ngIf="formAccountDetails.controls.full_name.touched && !formAccountDetails.controls.full_name.valid && !formAccountDetails.controls.full_name.pristine" class="errors">
...
</span>
He mejorado un poco la solución de Alex Shestakov, que ya funcionó por cierto, para evitar establecer el estado de control como válido cuando su valor cambia mientras mantiene el foco.
@Directive({
selector: ''[validate-onblur]'',
host: {
''(focus)'': ''onFocus($event)'',
''(blur)'' : ''onBlur($event)''
}
})
export class ValidateOnBlurDirective {
private validators: any;
private asyncValidators: any;
private hasFocus = false;
constructor(public formControl: NgControl) {
}
onFocus($event) {
this.hasFocus = true;
this.validators = this.formControl.control.validator;
this.asyncValidators = this.formControl.control.asyncValidator;
this.formControl.control.clearAsyncValidators();
this.formControl.control.clearValidators();
this.formControl.control.valueChanges
.filter(() => this.hasFocus)
.subscribe(() => this.formControl.control.markAsPending());
}
onBlur($event) {
this.hasFocus = false;
this.formControl.control.setAsyncValidators(this.asyncValidators);
this.formControl.control.setValidators(this.validators);
this.formControl.control.updateValueAndValidity();
}
}
De esta forma, el control permanecerá en estado pendiente mientras mantenga el foco. Eso ayudará a evitar el caso de que un control no sea válido antes de que se enfoque y luego, tan pronto como el usuario comience a escribir en él, se marca como válido, antes de que ocurra el evento de desenfoque, cuando los validadores se vuelven a configurar y la validez real de El control debe ser determinado.
Puedes
[class.has-error]="!form.controls[''ctrlEmailAddress''].valid"
Esto agregará la clase has-error tan pronto como cambie el modelo. Así que, básicamente, no necesitas difuminar para tener una verificación de validación.
Este problema resuelto con angular 2.0.0 beta;)
EDITAR 2
Como dice
Alex
y la
documentación oficial
, la
versión 5.0.0 de Angular
tiene una nueva opción para su actualización
updateOn: ''blur''
this.email = new FormControl(null, {
validators: Validators.required,
updateOn: ''blur''
});
También puede usar otras opciones de actualización:
change
(predeterminado),
blur
,
submit
.
Original
Uso la directiva donde elimino toda la validación en foco y la devuelvo después del evento de desenfoque. Se basa en la respuesta de Cristian Deschamps.
Actualizo la validez solo en el desenfoque, por lo que si el valor no era válido antes del enfoque, no lo será después. Pero si comienza la entrada, la validez se actualizará.
Por alguna razón, el orden de limpieza tiene sentido, así que primero borro los validadores asíncronos.
Cualquier sugerencia proporcionada será útil =)
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();
}
}
Además, esté atento a este hilo de github de Angular 2 sobre la validación de onBlur
EDITAR 1
Existe otro problema: si solo hago clic en el campo y después de hacer clic fuera, se llamará a la validación.
Si tiene alguna notificación al respecto (o llamadas al servidor), aparecerá cada vez que lo haga.
Entonces puede agregar la propiedad
wasChanged
y usarla así:
@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();
}
}