web-dev-qa-db-ja.com

Angular 4 Reactive Forms Toggle Validation for Hidden Form Elements

ロード時にフィールドが不要なリアクティブフォームがあります。 formGroupに追加のフォーム要素を追加するオプションが選択されている場合、新しい表示フィールドはすべて必須です。ニックネームフィールドが非表示になっている場合は、フォームを問題なく送信できるはずです。ニックネームが表示される場合、ニックネームフィールドは必須であり、ニックネームフィールドがいっぱいになるまで送信ボタンは無効になります。これが私がやりたいことのサンプルです。

私の質問は、フォーム要素が表示/非表示になったら検証を有効/無効にするにはどうすればよいですか?

App.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule, ReactiveFormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

App.component.ts

import { Component, OnInit } from '@angular/core';
import { Validators, FormControl, FormGroup, FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'My Reactive Form';

  constructor(
    private fb: FormBuilder
  ) {}

  myForm: FormGroup;
  showNick: boolean = false;

  ngOnInit() {
    this.myForm = this.fb.group({
      'firstName': new FormControl(),
      'nickName': new FormControl('', Validators.required),
      'lastName': new FormControl()
    })
  }

  toggleNick() {
    this.showNick = !this.showNick;
  }
}

app.component.html

<form [formGroup]="myForm">
  <div class="my-box">
    <label>
      First Name
      <input type="text" formControlName="firstName">
    </label>
  </div>
  <div class="my-box nickname">
    Nickname? &nbsp; <a (click)="toggleNick()">yes / no</a>
  </div>
  <div class="my-box" *ngIf="showNick">
    <label>
      Nickname
      <input type="text" formControlName="nickName">
      <span class="validation-message" *ngIf="!myForm.controls['nickName'].valid && myForm.controls['nickName'].dirty">
    This field is invalid
  </span>
    </label>
  </div>
  <div class="my-box">
    <label>
      Last Name
      <input type="text" formControlName="lastName">
    </label>
  </div>
  <button [disabled]="myForm.invalid">Submit</button>
</form>
8
iChido

私のアプリケーションでは、同様の要件があります。ユーザーがテキストによる通知を要求する場合、電話が必要です。それ以外の場合、電話番号はオプションです。

私はこのメソッドを書きました:

setNotification(notifyVia: string): void {
    const phoneControl = this.customerForm.get('phone');
    if (notifyVia === 'text') {
        phoneControl.setValidators(Validators.required);
    } else {
        phoneControl.clearValidators();
    }
    phoneControl.updateValueAndValidity();
}

NgOnInitにあるこのコードから呼び出されます:

    this.customerForm.get('notification').valueChanges
                     .subscribe(value => this.setNotification(value));

ユーザーが通知フィールド(ラジオボタン)を変更すると、値を渡してsetNotificationメソッドを呼び出します。値が「テキスト」による通知の場合、電話の検証を必須に設定します。

それ以外の場合は、電話フィールドの検証をクリアします。

次に、mustupdateValueAndValidityを呼び出して、この新しい検証でフォーム情報を更新します。

17
DeborahK

フィールドはユーザーから隠されていて、フィールドはリアクティブからアクティブになっています。したがって、次のコードを使用して、リアクティブからフィールドを無効にする必要があります

this.myForm.get("nickName").disable();

以下に示すように、関数toggleNick()を変更します

toggleNick() {
    this.showNick = !this.showNick;
    if(showNick) {
         this.myForm.get("nickName").enable();
    } else {
         this.myForm.get("nickName").disable();
    }
}
12
vivekkurien

これを行うための最良のオプションは、すべての検証でフィールドを初期フォームの一部にし、フィールドまたはネストされたフォームをプログラムで無効および有効にする場合です。

例: https://stackblitz.com/edit/angular-ojebff

https://stackblitz.com/edit/angular-ojebff?embed=1&file=app/input-errors-example.html

2
andy

複雑な形式のオプションフィールドがたくさんある場合、これらのソリューションが実行可能だとは思いませんでした。

私がやったのは、そのようなsomthehingです:

export class MyComponent implements AfterViewChecked {

 @ViewChildren(FormControlName) allFormControlInDOM: QueryList<FormControlName>;

 // ...

  ngAfterViewChecked(): void {
    // We must disable the controls that are not in the DOM
    // If we don't, they are used for validating the form
    if (this.allFormControlInDOM) {
      const controls: { [p: string]: AbstractControl } = this.myForm.controls;
      for (const control in controls) {
        if (controls.hasOwnProperty(control) && controls[control] instanceof FormControl) {
          const found = this.allFormControlInDOM.find((item: FormControlName) => item.name === control);
          if (found) {
            controls[control].enable();
          } else {
            controls[control].disable();
            controls[control].setValue(null);
          }
        }
      }
    }
  }

// ...

}

私はそれが役立つことを願っています:)

0
Klem231188