web-dev-qa-db-ja.com

Angular 4-リアクティブフォームの有効化/無効化が機能しない

アプリケーションでフォームコントロールを有効または無効にできません。これはおそらく、フォームが非同期コンテキストで有効/無効にされているためです。

コードは次のとおりです。

user.component.html

_<form [formGroup]="form">
    <input type="text" id="name" formControlName="name" />
    <input type="text" id="age" formControlName="age" />
</form>
_

user.component.ts

_ngOnInit() {

     this._route.queryParams.subscribe(params => {
            getUser(params.userId).subscribe(user => {
                 this._buildForm(user);
            })
     });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    })
}    
_

ユーザーがパラメーターの変更時に初めて読み込まれるとき、コントロールは関連する条件に基づいて有効/無効になります。その後パラメータが変更されても、値は適切に設定されていますが、コントロールの状態は同じです。

私はこれを修正するためにさまざまな方法を試しましたが、助けにはなりません。たとえば、__buildForm_メソッドの最後で次のことを試しました。

_this.form.disable() //Doesn't do anything

this.form.controls.name.disable(); //Doesn't help
_

期待どおりに機能する1つのことは次のとおりです(ただし、これは必須ではありません)。

_<button (click)="form.disable()" value="Disable Form" />
<button (click)="form.enable()" value="Enable Form" />
_

私が感じるのは、問題は_buildForm()が非同期コンテキスト(subscribeメソッド)から呼び出されているという事実によるものだと思います。

この問題を解決するにはどうすればよいですか?

[〜#〜]更新[〜#〜]

Observableサブスクリプションは、以下のナビゲーションに基づいてトリガーされることに注意してください。

_this._router.navigate([], {
   relativeTo: this._route,
   queryParams: {userId: 10}
})
_

UPDATE 2https://angular-cvf1fp.stackblitz.io

これは私の問題を理解する簡単な方法です

6
Kashif Nazar

あなただけのフォームコントロールの有効化/無効化メソッドが必要です。

これがstackblitz example です。それは完全に動作します。

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  group;
  isDisabled = true;

  constructor(fb: FormBuilder) {
    this.group = fb.group({
      stuff: fb.control({value: 'stuff', disabled: this.isDisabled})
    });
  }

  toggle() {
    this.isDisabled = !this.isDisabled;

    this.group.controls.stuff[this.isDisabled ? 'enable' : 'disable']();
  }
}
3

あなたが正しい。サブスクリプションは一度だけ発生するため、フォームを送信した後、ユーザーエンティティは変更されません。これを行うには、たとえば、フォーム送信にイベントハンドラを追加します。

ser.component.html

<form [formGroup]="form" (submit)="_updateForm()">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

ser.component.ts

private userId: any;


ngOnInit() {
    this._route.queryParams.subscribe(params => {
        this.userId = params.userId;
        this._updateForm();
    });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    });
} 

// The update function has to be public to be called inside your template
public _updateForm(){
    getUser(this.userId).subscribe(user => {
        this._buildForm(user);
    });
}    
2
<form [formGroup]="form">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

ここにタイプミスがありますか?fromControlNameformControlNameになるはずです変更後、切り替えが機能します;)

https://angular-rivxs5.stackblitz.io

1
Antoniossss
  • formGroupngOnitを直接作成します。デフォルトでは無効になっているため、非同期の問題を心配せずに存在することが確認できます。
  • this._route.queryParams.subscribe(...)では、this.form.setValue({//set all control values})またはthis.form.patchValue({//set individual controls})を使用して、必要に応じて、または利用可能になったら、個々のコントロールを更新できます。
  • conditionおよびsomeOtherConditionのコンポーネントインスタンス変数を使用します(または、データモデルをフォームのモデルから分離したい場合は、全体としてuserオブジェクトを使用します。同じである)。これらを「false」に初期化し、代わりにformGroup作成でコントロールを有効/無効にするために参照してください。 userデータモデルへの直接のアクセスを待つのではなく、ユーザーデータが配置されたら、同じ.subscribe()ブロック内のこれらの変数を更新することもできます。

このようにして、非同期データが利用可能になるまで、コントロールとformGroupが存在し、無効になります。

1
mc01