web-dev-qa-db-ja.com

FormGroupにパッチを適用するときにAngular Reactive Forms PatchValue()がnull値または未定義を無視するようにする方法

構築しているアプリケーションの場合、APIからデータを取得し、その応答を使用してフォーム値を直接設定しています。そのために、私はリアクティブフォームモジュールを使用しています。 APIから取得するオブジェクトと一致するようにフォームを作成しました。問題は、一部のフィールドがオブジェクト(FormGroup)であると想定されているが、空の場合はNULLになることです。これにより、「未定義またはnullをオブジェクトに変換できません」というエラーが発生します。

FormGroupインスタンス:

note: this.formBuilder.group({
   turnbook_file: [''],
   note: [''],
   additional_files: ['']
});

APIからの応答

note: NULL

私の考えでは、ORステートメントなど、FormGroupを次のように定義する場所に配置することは可能かもしれません。

note: this.formBuilder.group({
   turnbook_file: [''],
   note: [''],
   additional_files: ['']
} | NULL);
6
Thom

Lodash pickByメソッドを使用して、API応答を使用する前にラップしてみることができます。

import * as _ from 'lodash';
...
//fetch data from API
note.patchValue(
    _.pickBy(apiResponse)
);
...
1
bestbrain10

短い答え:Angular FormsAPIの現在の実装では-FormGroupnullまたはundefinedの値。

理由:すべてのシナリオでnew FormGroup(), formBuilder.group(), patchValue()などのメソッドObject.keys()が呼び出され、エラーがスローされます_Cannot convert undefined or null to object_を引数として渡す場合は_null/undefined_(JS仕様による)。

証明

  • FormBuildergroup()メソッド( ソースコードリンク ):

    _  group(controlsConfig: {[key: string]: any}, ...) {
        const controls = this._reduceControls(controlsConfig);
        ...
      }
      _reduceControls(controlsConfig: {[k: string]: any}) {
        Object.keys(controlsConfig).forEach(...);
        ...
      }
    _
  • FormGroup's patchValueソースコードリンク ):

    _patchValue(value: {[key: string]: any}, ...) {
      Object.keys(value).forEach(...);
      ...
    }
    _

回避策

  • バックエンド側のAPI応答を変更して、nullではなく空のオブジェクト_{}_を送信するようにします。
  • フロントエンド側で応答を受信したら、次のマッピングを実行できます。nullから{};
  • FormGroupクラスを拡張し、_constructor/patchValue_をオーバーライドできる新しいクラスを作成します。引数が_null/undefined_であるかどうかを確認します-代わりに空のオブジェクトを使用します。
  • FormBuilderサービスを拡張し、groupメソッドをオーバーライドできる独自のシングルトンサービスを作成します(アプリ内のあらゆる場所で使用します)(前のポイントを参照)。
0
shohrukh

フォームとコントロールを定義する場合は、それに値を渡す必要があるため、応答がnullの場合は、次のようにフォームコントロールの値を設定します。

note.setValue({
'turnbook_file': data.turnbook_file == null ? "": data.turnbook_file,
   'note: ,data.note == null ? "": data.note,
   'additional_files': data.additional_files == null ? "": 
    data.additional_files,
})
0
Prachi Shah

このようにフォームを定義できます

note =new FormGroup({
   'turnbook_file': new FormControl(null),
   'note: new FormControl(null),
   'additional_files': new FormControl(null)
})
0
Prachi Shah

2つの解決策が思い浮かびます

FormGroupプロトタイプを変更する

@NgModule({...})
export class AppModule {

  constructor() {
    const builtInFunction = FormGroup.prototype.patchValue;
    FormGroup.prototype.patchValue = function (value, options?) {
      builtInFunction.call(this, value || {}, options);
    }
  }

}

FormGroupクラスを拡張する

import {FormGroup, ValidatorFn, AbstractControlOptions, AsyncValidatorFn} from '@angular/forms';

export class MyFormGroup extends FormGroup {

  constructor(
    controls: {[key: string]: any},
    validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,
    asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null
  ) {
    super(controls, validatorOrOpts, asyncValidator);  
  }

  patchValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}) {
    super.patchValue(value || {}, options);
  }

}
0
displayName

フォームにパッチを適用する前に、これらの値を簡単に除外できます

const obj = {
  foo: "bar",
  bar: null,
  cat: undefined,
  dog: "bark"
}

const truthy = Object.keys(obj).filter(item => obj[item] != undefined || obj[item] != null );
const newObj = {};
truthy.forEach(item =>Object.assign(newObj, { [item]: obj[item]}));
console.log(newObj) // { foo: "bar", dog: "bark" }

偽の値を除外したら、それを使用してフォームにパッチを適用します

0
Adithya Sreyaj