Bagaimana saya bisa secara manual mengatur bidang formulir Sudut sebagai tidak valid?

190

Saya sedang mengerjakan formulir login dan jika pengguna memasukkan kredensial tidak valid kami ingin menandai bidang email dan kata sandi sebagai tidak valid dan menampilkan pesan yang mengatakan login gagal. Bagaimana cara menetapkan bidang ini menjadi tidak valid dari panggilan balik yang dapat diamati?

Templat:

<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>

Metode login:

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

Selain mengatur input flag yang tidak benar ke true Saya sudah mencoba mengatur email.validflag ke false, dan mengatur loginForm.invalidke true juga. Tidak satu pun dari ini menyebabkan input untuk menampilkan keadaan tidak valid mereka.

efarley
sumber
Apakah backend Anda pada port berbeda dari sudut? Jika demikian, ini mungkin masalah CORS. Kerangka apa yang Anda gunakan untuk backend.
Mike3355
Anda bisa menggunakan setErrosmetode. Tips: Anda harus menambahkan validator yang diperlukan pada file komponen Anda. Juga adakah alasan khusus untuk menggunakan ngModel dengan bentuk reaktif?
developer033
@ developer033 agak terlambat ke pesta di sini, tetapi itu tidak terlihat seperti Formulir Reaktif, tetapi formulir yang digerakkan Templat.
thenetimp

Jawaban:

261

dalam komponen:

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

dan dalam HTML:

<input mdInput placeholder="Email" type="email" name="email" required [(ngModel)]="email"  #email="ngModel">
<div *ngIf="!email.valid">{{email.errors| json}}</div>
Julia Passynkova
sumber
13
Dan bagaimana Anda menghapus kesalahan sesudahnya? setErrors({'incorrect': false})atau setErrrors({})tidak bekerja untuk saya
Robouste
3
Bisakah saya menetapkan seluruh formulir reaktif sebagai valid atau tidak valid daripada mengatur ulang bidang?
xtremist
29
@Robouste Anda dapat menghapus kesalahan secara manual dengansetErrrors(null)
Idrees Khan
6
Selain jawaban ini: kode ini tidak berfungsi untuk saya tanpa formData.form.controls['email'].markAsTouched();seperti @ M.Farahmand yang disebutkan di bawah ini. Gunakan setErrors({'incorrect': true})hanya mengatur ng-invalidkelas css untuk input. Saya harap ini membantu seseorang.
Barabas
4
Dan bagaimana jika ada lebih banyak validator, seperti "wajib" - apakah setErrors (null) menghapus kesalahan itu?
Please_Dont_Bully_Me_SO_Lords
87

Menambah jawaban Julia Passynkova

Untuk mengatur kesalahan validasi dalam komponen:

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

Untuk menghapus kesalahan validasi dalam komponen:

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

Berhati-hatilah dengan menghapus kesalahan menggunakan nullkarena ini akan menimpa semua kesalahan. Jika Anda ingin menyimpan beberapa di sekitar Anda mungkin harus memeriksa keberadaan kesalahan lain terlebih dahulu:

if (isIncorrectOnlyError){
   formData.form.controls['email'].setErrors(null);
}
Eric D.
sumber
3
Apakah mungkin untuk menghapus kesalahan validasi menggunakan sesuatu seperti formData.form.controls ['email']. SetErrors ({'salah': false});
rudrasiva86
1
Bagaimana dengan formulir reaktif?
seidme
26

Saya mencoba untuk memanggil setErrors()di dalam handler ngModelChange dalam formulir template. Itu tidak bekerja sampai saya menunggu satu tanda centang dengan setTimeout():

templat:

<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>

komponen:

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

Gotcha seperti ini membuat saya lebih suka bentuk reaktif.

Mark Rajcok
sumber
Cannot find name 'NgModel'.kesalahan untuk saluran @ViewChild('pwConfirmModel') pwConfirmModel: NgModel;perbaikan apa pun untuk masalah ini
Deep 3015
Ada apa dengan harus menggunakan setTimeOuts? Saya perhatikan ini dan tampaknya kontrol tidak segera memperbarui diri. Ini memperkenalkan banyak kode hacky untuk mengatasi keterbatasan ini.
Jake Shakesworth
Terima kasih. Saya tahu setErrorstetapi itu tidak berhasil sampai saya menggunakansetTimeout
Sampgun
25

Dalam versi baru materi 2 yang nama kontrolnya dimulai dengan awalan mat setErrors () tidak berfungsi, sebagai gantinya jawaban Juila dapat diubah menjadi:

formData.form.controls['email'].markAsTouched();
M_Farahmand
sumber
1

Berikut ini contoh yang berfungsi:

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] ]
  });
}
Roman Tidak ada
sumber
Ini mungkin "hacky", tapi saya suka karena Anda tidak perlu mengatur ErrorStateMatcher kustom untuk bekerja dengan kesalahan Input Bahan Angular!
David Melin
1

Dalam formulir Reaktif saya, saya perlu menandai bidang sebagai tidak valid jika bidang lain diperiksa. Dalam ng versi 7 saya melakukan hal berikut:

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

Jadi di atas, ketika saya mencentang kotak itu mengatur dropdown seperti yang diperlukan dan menandainya sebagai kotor. Jika Anda tidak menandainya, maka tidak akan salah (salah) sampai Anda mencoba mengirim formulir atau berinteraksi dengannya.

Jika kotak centang disetel ke false (tidak dicentang) maka kami menghapus validator yang diperlukan pada dropdown dan meresetnya ke keadaan murni.

Juga - ingatlah untuk berhenti berlangganan dari perubahan bidang pemantauan!

Katana24
sumber
1

Anda juga dapat mengubah 'type' viewChild ke NgForm seperti pada:

@ViewChild('loginForm') loginForm: NgForm;

Dan kemudian referensi kontrol Anda dengan cara yang sama seperti yang disebutkan oleh @Julia:

 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'].setErrors({ 'incorrect': true});
      this.loginForm.controls['password'].setErrors({ 'incorrect': true});
    });
  }

Mengatur Kesalahan ke nol akan menghapus kesalahan pada UI:

this.loginForm.controls['email'].setErrors(null);
Jacques
sumber
0

Meskipun solusi yang terlambat tetapi berikut berhasil dari saya.

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

Untuk unit test:

spyOn(component.form, 'valid').and.returnValue(true);
Vang Bờm
sumber