ロード時にフィールドが不要なリアクティブフォームがあります。 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? <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>
私のアプリケーションでは、同様の要件があります。ユーザーがテキストによる通知を要求する場合、電話が必要です。それ以外の場合、電話番号はオプションです。
私はこのメソッドを書きました:
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
を呼び出して、この新しい検証でフォーム情報を更新します。
フィールドはユーザーから隠されていて、フィールドはリアクティブからアクティブになっています。したがって、次のコードを使用して、リアクティブからフィールドを無効にする必要があります
this.myForm.get("nickName").disable();
以下に示すように、関数toggleNick()を変更します
toggleNick() {
this.showNick = !this.showNick;
if(showNick) {
this.myForm.get("nickName").enable();
} else {
this.myForm.get("nickName").disable();
}
}
これを行うための最良のオプションは、すべての検証でフィールドを初期フォームの一部にし、フィールドまたはネストされたフォームをプログラムで無効および有効にする場合です。
例: https://stackblitz.com/edit/angular-ojebff
https://stackblitz.com/edit/angular-ojebff?embed=1&file=app/input-errors-example.html
複雑な形式のオプションフィールドがたくさんある場合、これらのソリューションが実行可能だとは思いませんでした。
私がやったのは、そのような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);
}
}
}
}
}
// ...
}
私はそれが役立つことを願っています:)