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