web-dev-qa-db-ja.com

検証を使用してフォームを複数のコンポーネントに分割する

angular 2で1つの大きなフォームを作成します。しかし、次の例に示すように、複数のコンポーネントでこのフォームを作成します。

アプリコンポーネント

<form novalidate #form1="ngForm" [formGroup]="myForm">
<div>
    <address></address>
</div>
<div>
    <input type="text" ngModel required/>
</div>

<input type="submit" [disabled]="!form1.form.valid" > </form>

アドレスコンポーネント

<div>
<input type="text" ngModel required/> </div>

上記のコードを使用すると、必要に応じてブラウザに表示されましたが、アドレスコンポーネントのテキストを削除しても送信ボタンは無効になりませんでした。
ただし、アプリコンポーネントの入力ボックスのテキストを削除すると、ボタンは正しく無効になりました。

42
Lasitha Yapa

私は非常にうまく機能するリアクティブフォームを使用し、あなたのコメントに関しては:

このための他の簡単な例はありますか?たぶん、ループなしの同じ例

例を挙げましょう。必要なことは、FormGroupをネストし、それを子に渡すことです。

フォームが次のようになり、address formgroupを子に渡すとします。

ngOnInit() {
  this.myForm = this.fb.group({
    name: [''],
    address: this.fb.group({ // create nested formgroup to pass to child
      street: [''],
      Zip: ['']
    })
  })
}

次に、親で、ネストされたフォームグループを渡すだけです:

<address [address]="myForm.get('address')"></address>

子では、ネストされたフォームグループに@Inputを使用します。

@Input() address: FormGroup;

そして、テンプレートで[formGroup]を使用します:

<div [formGroup]="address">
  <input formControlName="street">
  <input formControlName="Zip">
</div>

実際のネストされたフォームグループを作成したくない場合は、作成する必要はありません。その場合、フォームを次のようにすると、親フォームを子に渡すことができます。

this.myForm = this.fb.group({
  name: [''],
  street: [''],
  Zip: ['']
})

任意のコントロールを渡すことができます。上記と同じ例を使用して、streetZipのみを表示します。子コンポーネントは同じままですが、テンプレートの子タグは次のようになります。

<address [address]="myForm"></address>

これは

デモ最初のオプション、ここに2番目のオプションデモ

詳細情報 here ネストされたモデル駆動型フォームについて。

67
AJT_82

私の経験から、この種のフォームフィールドの構成は、テンプレート駆動型のフォームでは作成が困難です。住所コンポーネントに埋め込まれたフィールドはフォーム(NgForm.controlsオブジェクト)に登録されないため、フォームの検証時に考慮されません。

  • すべての検証でControlValueAccessorコンポーネント(ngModel属性を受け入れる)を作成できますが、検証エラーを表示して変更を伝達することは困難です(アドレスは複雑な値を持つ単一のフォームフィールドと見なされます)。
  • おそらくフォーム参照をAddressコンポーネントに渡して内部コントロールを登録することもできますが、私はそれを試したことはなく、奇妙なアプローチのようです(どこにも見たことがない)。
  • (テンプレート駆動型の代わりに)リアクティブフォームに切り替え、フォームグループオブジェクト(アドレスを表す)をAddressコンポーネントに渡し、フォーム定義の検証を維持できます。ここに例を見ることができます https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2
6
Ján Halaša

テンプレート駆動フォームでもそれを行う方法があります。 ngModelは各コンポーネントに個別のフォームを自動的に作成しますが、これをコンポーネントに追加することにより、親コンポーネントのフォームを挿入できます。

@Component({
viewProviders: [{ provide: ControlContainer, useExisting: NgForm}]
}) export class ChildComponent

ただし、各入力に一意の名前が付けられていることを確認する必要があります。そのため、* ngForを使用して子コンポーネントを呼び出す場合は、インデックス(またはその他の一意の識別子)を名前に入れる必要があります(例:

[name]="'address_' + i"

フォームをFormGroupsに構造化する場合は、ngModelGroupと

viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }]

ngFormの代わりに[ngModelGroup]="yourNameHere"をタグを含むいくつかの子コンポーネントhtmlに追加します。

3
Jeremy Benks

私の場合の仕事をしたアプローチを共有したいと思います。次のディレクティブを作成しました:

import { Directive } from '@angular/core';
import { ControlContainer, NgForm } from '@angular/forms';

@Directive({
  selector: '[appUseParentForm]',
  providers: [
    {
      provide: ControlContainer,
      useFactory: function (form: NgForm) {
        return form;
      },
      deps: [NgForm]
    }
  ]
})
export class UseParentFormDirective {
}

次に、子コンポーネントでこのディレクティブを使用する場合、たとえば:

<address app-use-parent-form></address>

addressComponentのコントロールがform1に追加されます。結果として、フォームの有効性は、子コンポーネント内のコントロールの状態にも依存します。

Angular 6でのみチェックされます

3
Maczaj Srtgth