web-dev-qa-db-ja.com

AngularでControlValueAccessorを実装するときに、writeValueでonChangeとonTouchを呼び出す必要があるのはなぜですか?

次のコンポーネントを実装しました。期待どおりに動作します。それでも、ControlValueAccessorの実装は私にとって初めてだったので、いくつかのセクションの詳細を理解せずに ブログをフォロー しなければなりませんでした。つまり、これは「動作しますが、なぜですか?!」という状況の一種です。

_@Component({ selector: ..., templateUrl: ..., styleUrls: ...,
  providers: [{ provide: NG_VALUE_ACCESSOR, 
                useExisting: forwardRef(() => InputTextComponent), 
                multi: true }]
})
export class InputComponent implements ControlValueAccessor {

  constructor() { }
  @Input() info: string;
  onChange: any = () => { }
  onTouch: any = () => { }

  writeValue(input: any): void {
    this.info.value = input;
    // this.onChange(input);
    // this.onTouch();
  }

  registerOnChange(_: any): void { this.onChange = _; }
  registerOnTouched(_: any): void { this.onTouch = _; }

  setDisabledState?(state: boolean): void { }

  onEdit(value: string): void { this.onChange(value); }
}
_

動作するようになったら、writeValue(...)メソッドの2行目と3行目をコメントアウトしましたが、私が知る限り、何も壊れていませんでした。これらの呼び出しは 他のブログ によっても一貫して提案されているので、それらを省略することは不適切であると私は確信しています。しかし、私は魔法を信じておらず、物事を行う具体的な理由があることを好みます。

onChange(...)onTouch(...)およびwriteValue(...)の呼び出しを実行することが重要なのはなぜですか。何がうまくいかず、どのような状況でそれが予想されますか?

サイドクエストとして、私もコメントアウトしようとしました 他のメソッド そしてsetDisabledState(...)を削除したとき、バナナが行くことを何も言えないことを発見しました。それはいつ問題を引き起こすと予想できますか?本当に実装する必要がありますか(括弧の前後に疑問符が付いたバージョンで、setDisabledState?(state: boolean): void { }のようなパラメーターがありますが、setDisabledState(state: boolean)?: void { }のようなものもあります)。

8
DonkeyBanana

ControlValueAccessorについて詳しく説明しているこの記事を読んでください。

コンポーネントがAngularフォームの一部として使用されることになっている場合は、通常、コンポーネントにControlValueAcceessorインターフェイスを実装する必要があります。

WriteValue(...)メソッドの2行目と3行目をコメントアウトしましたが、私が知る限り、何も壊れていませんでした。

これはおそらく、フォームディレクティブ(formControlをカスタム入力コンポーネントにリンクするngModelまたはFormControl)を適用していないためです。 FormControlは、通信にwriteValueInputComponentメソッドを使用します。

これが私が上で参照した記事からの写真です:

enter image description here

writeValueメソッドはformControlによって使用され、ネイティブフォームコントロールに値を設定します。 registerOnChangeメソッドはformControlによって使用され、ネイティブフォームコントロールが更新されるたびにトリガーされると予想されるコールバックを登録します。 registerOnTouchedメソッドは、ユーザーがコントロールを操作したことを示すために使用されます。

WriteValue(...)でonChange(...)およびonTouch(...)の呼び出しを実行することが重要なのはなぜですか?何がうまくいかず、どのような状況でそれが予想されますか?

これは、ControlValueAcceessorを実装するカスタムコントロールがAngularのFormControlに、入力の値が変更されたか、ユーザーがコントロールを操作したことを通知するメカニズムです。

... setDisabledState(...)を削除したときに、バナナが行くことを何も言えないことがわかりました...本当に実装する必要がありますか?

インターフェイスで指定されているように、この関数は、制御ステータスが「DISABLED」に変更されたとき、または「DISABLED」から変更されたときに、フォームAPIによって呼び出されます。値に応じて、適切なDOM要素を有効または無効にする必要があります。関連するFormControlのステータスがdisabledになるたびに通知を受け取りたい場合は、これを実装する必要があります。その後、カスタムロジックを実行できます(たとえば、入力コンポーネントを無効にします)。

15
Maxim Koretskyi

受け入れられた答えが最も中心的な質問に簡潔に答えるとは思いません。

WriteValue(...)でonChange(...)およびonTouch(...)の呼び出しを実行することが重要なのはなぜですか?

そうではありません。 writeValueでonChangeを呼び出す必要はありません。これは意図された使用法ではありません(以下のドキュメントリンクを参照)。

何がうまくいかず、どのような状況でそれが予想されますか?

何も問題がないことを期待してください。手の込んだ答え:

onChangeの内部からwriteValueを呼び出すと、次のことがわかります。

  • 最初のonChange呼び出しは何もしません。これは、writeValueが最初に呼び出されたときに、onChangeコールバックが登録されていない(つまり、registerOnChangeが呼び出されていない)ためです。
  • 後でwriteValue内からonChangeを呼び出すと、モデルが更新されます(emitModelToViewChange = falseモデルから指定した値(受け取ったばかり)を使用してwriteValue)を再帰的に呼び出さないようにします。

言い換えると、コンポーネントがwriteValueで受け取る値を何らかの方法ですぐに変更し、それらの変更をモデルに戻すためにコンポーネントに依存しない限り、onlyonsecond以降のwriteValueの呼び出しでは、writeValueからonChangeを呼び出さなくても安全です。

こちらのドキュメントの例を参照してください: https://angular.io/api/forms/ControlValueAccessor

1
corolla