web-dev-qa-db-fra.com

Comment définir manuellement un champ de formulaire angulaire comme non valide?

Je travaille sur un formulaire de connexion et si l'utilisateur entre des informations d'identification non valides, nous souhaitons marquer les champs d'adresse e-mail et de mot de passe comme non valides et afficher un message indiquant que la connexion a échoué. Comment définir des champs non valides à partir d'un rappel observable?

Modèle:

<form #loginForm="ngForm" (ngSubmit)="login(loginForm)" id="loginForm">
  <div class="login-content" fxLayout="column" fxLayoutAlign="start stretch">
    <md-input-container>
      <input mdInput placeholder="Email" type="email" name="email" required [(ngModel)]="email">
    </md-input-container>
    <md-input-container>
      <input mdInput placeholder="Password" type="password" name="password" required [(ngModel)]="password">
    </md-input-container>
    <p class='error' *ngIf='loginFailed'>The email address or password is invalid.</p>
    <div class="extra-options" fxLayout="row" fxLayoutAlign="space-between center">
     <md-checkbox class="remember-me">Remember Me</md-checkbox>
      <a class="forgot-password" routerLink='/forgot-password'>Forgot Password?</a>
    </div>
    <button class="login-button" md-raised-button [disabled]="!loginForm.valid">SIGN IN</button>
     <p class="note">Don't have an account?<br/> <a [routerLink]="['/register']">Click here to create one</a></p>
   </div>
 </form>

Méthode de connexion:

 @ViewChild('loginForm') loginForm: HTMLFormElement;

 private login(formData: any): void {
    this.authService.login(formData).subscribe(res => {
      alert(`Congrats, you have logged in. We don't have anywhere to send you right now though, but congrats regardless!`);
    }, error => {
      this.loginFailed = true; // This displays the error message, I don't really like this, but that's another issue.
      this.loginForm.controls.email.invalid = true;
      this.loginForm.controls.password.invalid = true; 
    });
  }

En plus de définir l'indicateur d'entrée invalide sur true, j'ai essayé de définir l'indicateur email.valid sur false et de définir le loginForm.invalid sur true. Aucune de celles-ci ne provoque l'affichage d'invalidité des entrées.

80
efarley

en composant:

formData.form.controls['email'].setErrors({'incorrect': true});

et en html:

<input mdInput placeholder="Email" type="email" name="email" required [(ngModel)]="email"  #email="ngModel">
<div *ngIf="!email.valid">{{email.errors| json}}</div>
119
Julia Passynkova

Ajout à la réponse de Julia Passynkova

Pour définir une erreur de validation dans le composant:

formData.form.controls['email'].setErrors({'incorrect': true});

Pour annuler l'erreur de validation dans le composant:

formData.form.controls['email'].setErrors(null);

Soyez prudent avec la suppression des erreurs en utilisant 'null' car cela écrasera toutes les erreurs. Si vous voulez en garder quelques-unes, vous devrez d'abord vérifier l'existence d'autres erreurs:

if(isIncorrectOnlyError){
   formData.form.controls['email'].setErrors(null);
}
49
Eric D.

J'essayais d'appeler setErrors() dans un gestionnaire ngModelChange dans un formulaire. Cela n'a pas fonctionné jusqu'à ce que j'attende un tick avec setTimeout():

modèle:

<input type="password" [(ngModel)]="user.password" class="form-control" 
 id="password" name="password" required (ngModelChange)="checkPasswords()">

<input type="password" [(ngModel)]="pwConfirm" class="form-control"
 id="pwConfirm" name="pwConfirm" required (ngModelChange)="checkPasswords()"
 #pwConfirmModel="ngModel">

<div [hidden]="pwConfirmModel.valid || pwConfirmModel.pristine" class="alert-danger">
   Passwords do not match
</div>

composant:

@ViewChild('pwConfirmModel') pwConfirmModel: NgModel;

checkPasswords() {
  if (this.pwConfirm.length >= this.user.password.length &&
      this.pwConfirm !== this.user.password) {
    console.log('passwords do not match');
    // setErrors() must be called after change detection runs
    setTimeout(() => this.pwConfirmModel.control.setErrors({'nomatch': true}) );
  } else {
    // to clear the error, we don't have to wait
    this.pwConfirmModel.control.setErrors(null);
  }
}

Les pièges comme celui-ci me font préférer les formes réactives.

13
Mark Rajcok

Dans la nouvelle version du matériau 2 dont le nom de contrôle commence par le préfixe mat setErrors () ne fonctionne pas, la réponse de Juila peut être modifiée en:

formData.form.controls['email'].markAsTouched();
11
M.Farahmand

Voici un exemple qui fonctionne:

MatchPassword(AC: FormControl) {
  let dataForm = AC.parent;
  if(!dataForm) return null;

  var newPasswordRepeat = dataForm.get('newPasswordRepeat');
  let password = dataForm.get('newPassword').value;
  let confirmPassword = newPasswordRepeat.value;

  if(password != confirmPassword) {
    /* for newPasswordRepeat from current field "newPassword" */
    dataForm.controls["newPasswordRepeat"].setErrors( {MatchPassword: true} );
    if( newPasswordRepeat == AC ) {
      /* for current field "newPasswordRepeat" */
      return {newPasswordRepeat: {MatchPassword: true} };
    }
  } else {
    dataForm.controls["newPasswordRepeat"].setErrors( null );
  }
  return null;
}

createForm() {
  this.dataForm = this.fb.group({
    password: [ "", Validators.required ],
    newPassword: [ "", [ Validators.required, Validators.minLength(6), this.MatchPassword] ],
    newPasswordRepeat: [ "", [Validators.required, this.MatchPassword] ]
  });
}
1
Roman None

Bien que sa solution tardive mais la solution suivante a fonctionné me forment.

    let control = this.registerForm.controls['controlName'];
    control.setErrors({backend: {someProp: "Invalid Data"}});
    let message = control.errors['backend'].someProp;
0
Dila Gurung

Dans mon formulaire réactif, je devais marquer un champ comme invalide si un autre champ était coché. Dans la version 7, j'ai fait ce qui suit:

    const checkboxField = this.form.get('<name of field>');
    const dropDownField = this.form.get('<name of field>');

    this.checkboxField$ = checkboxField.valueChanges
        .subscribe((checked: boolean) => {
            if(checked) {
                dropDownField.setValidators(Validators.required);
                dropDownField.setErrors({ required: true });
                dropDownField.markAsDirty();
            } else {
                dropDownField.clearValidators();
                dropDownField.markAsPristine();
            }
        });

Donc, ci-dessus, lorsque je coche la case, le menu déroulant est défini comme requis et marqué comme sale. Si vous ne le marquez pas comme tel, il ne sera pas invalide (par erreur) jusqu'à ce que vous essayiez de soumettre le formulaire ou d'interagir avec celui-ci.

Si la case à cocher est définie sur false (non cochée), nous effaçons le validateur requis dans la liste déroulante et le réinitialisons à un état parfait.

Aussi - n'oubliez pas de vous désabonner de la surveillance des modifications de champ!

0
Katana24