Angular2 - validation FormControl sur flou

je cherche à ajouter une validation basique de courriel pour vérifier que l'Utilisateur a mis une adresse de courriel correcte. Actuellement en utilisant la méthode ci-dessous, la validation se met à jour comme les types d'utilisateurs, ce qui semble étrange quand il y a des erreurs après avoir entré un caractère.

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]));

je me demandais s'il était possible de déclencher la validation sur flou du champ, comme dans angularJS avec:

ng-model-options="{ updateOn: 'blur' }"

je suis au courant de l'option flou sur le champ d'entrée dans le html mais cela ne mettre mon contrôle d'erreur, sauf s'il existe un moyen de placer la commande dans un état d'erreur.

Quelqu'un pourrait-il m'aider à m'orienter dans la bonne direction?

Merci.

Edit: je cherche une solution angular2, pas une solution angularJS.

26
demandé sur AJT_82 2015-11-23 11:49:15

6 réponses

EDIT 2

Alex et documents officiels dit version angulaire 5.0.0 a une nouvelle option pour votre ngModel updateOn: 'blur'

this.email = new FormControl(null, {
   validators: Validators.required,
   updateOn: 'blur'
});

vous pouvez Aussi utiliser d'autres options de mise à jour: change (par défaut), blur,submit.


Origine

j'utilise la directive where remove whole validation on focus et je la renvoie après l'événement flou. Il d'après la réponse de Cristian Deschamps.

je l'ai mise à jour de validité que sur le flou, donc si la valeur est invalide avant de se concentrer, il ne sera pas valide après. Mais si vous commencez la saisie, la validité sera mise à jour.

pour certaines raisons, l'autorisation de l'ordre a du sens, donc j'autorise d'abord les validateurs asynchrones.

fournie suggestion sera utile =)

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();
    }
}

Aussi, s'il vous plaît restez à l'écoute sur ce fil 2 github angulaire A propos de onBlur validation


EDIT 1

il y a un autre problème - si je clique simplement sur le champ et qu'après un clic, la validation sera appelée. Si vous avez n'importe quelle notification à ce sujet (ou des appels de serveur) - il apparaîtrait chaque fois que vous le faites. Ainsi, vous pouvez ajouter wasChanged propriété et de l'utiliser comme ceci:

    @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();
        }
    }
35
répondu Alex Shestakov 2018-01-17 06:50:20

angle v5.0.0 c'est maintenant possible en marquant updateOn: 'blur' au contrôle de forme.

cela signifie aussi que valueChanges ne tire pas pour ce contrôle de forme jusqu'à ce que l'événement de flou se produit. Voici un exemple avec minlength avec required:

this.form = new FormGroup({
  username: new FormControl('', {
  validators: [Validators.required, Validators.minLength(6)], updateOn: 'blur'} )
})

get username() {
  return this.form.get('username');
}

dans le modèle, vous voulez marquer que le message de validation n'apparaîtra que si le champ est touched:

<div *ngIf="username.hasError('minlength') || username.hasError('required') 
              && username.touched">Required and minlength 6!
</div>

DEMO

P. S si nécessaire, vous pouvez également marquer ceci sur l'ensemble du Formulaire, pas seulement sur un contrôle de formulaire spécifique

8
répondu AJT_82 2017-12-30 11:13:16

quelque Chose comme ceci: Utilisez la propriété touché ngControl objet.

 <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>
6
répondu tomasz 2015-12-27 13:52:49

1-Créer une directive: 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);
    }
}

puis dans votre template html il suffit d'ajouter la directive à votre formulaire, mon exemple utiliser le modèle de Réactiveformsmodule.

puis ajoutez ceci à votre message d'erreur:

<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>
6
répondu Cristian Deschamps 2016-09-13 02:51:49

J'ai amélioré un peu la solution D'Alex Shestakov, qui fonctionnait déjà au passage, afin d'éviter de mettre l'état de contrôle à valide lorsque sa valeur change alors qu'il garde la mise au point.

@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 Cette façon, la commande reste en attente tant qu'il garde le focus. Cela aidera à éviter le cas où un contrôle est invalide avant qu'il n'obtienne la mise au point et puis dès que l'utilisateur commence à taper sur elle, il est marqué comme valide, avant que l'événement flou se produit, quand les validateurs sont remis en place et la validité réelle du contrôle doit être déterminée.

3
répondu Daniel Francisco Sabugal 2017-02-10 01:44:24

Vous pouvez

[class.has-error]="!form.controls['ctrlEmailAddress'].valid"

ceci ajoutera la classe has-error dès que vous changerez de model. Donc, en gros, vous n'avez pas besoin de flou pour avoir un contrôle de validation.

-4
répondu przemcio 2017-10-13 15:31:52