web-dev-qa-db-ja.com

ngFor内で反応フォームを使用する方法

ユーザーの配列は複数の要素(ユーザー)を持つことができます。テンプレートでは、この配列を反復処理して、各要素のフォームを追加します。現在、各フォームは同じフォームグループ値にバインドしています。最初のユーザーのフォームに入力すると、すべてのフォームの送信ボタンが有効になります。各フォームを一意のformGroupまたは一意の変数にポイントするにはどうすればよいですか?

成分:

import { FormControl, FormGroup, Validators, FormBuilder} from '@angular/forms';
...
export class UserComponent implements OnInit {
 form: FormGroup;
 @input users: any[];

 constructor(private _fb: FormBuilder) {}
 ngOnInit() {
  this.form = this._fb.group({
   address: new FormControl('', [Validators.required]),
   phone: new FormControl('', [Validators.required]),
   });
 }

 add() {
   if (this.form.valid){
     // code
   }
 }

テンプレート:

 <div *ngFor="let user if users">
  {{user.name}}
    <form [formGroup]="form"  (ngSubmit)="add()">         
     <div class="form-group">
       <label>Address:</label>
       <input formControlName="address" class="form-control">
       <label>Phone:</label>
       <input formControlName="phone" class="form-control"></input>
     </div>
     <button type="submit" class="submit" [disabled]="!form.valid">Submit</button>    
    </form>
 </div>
5

問題を解決するには、次のようにformArrayを使用する必要があります:

コンポーネント内:

export class UserComponent implements OnInit {
     usersForm: FormGroup;
     errorMessage : string;

     constructor(private formBuilder: FormBuilder) {}

      ngOnInit() {
          this.usersForm= this.formBuilder.group({
               users: this.formBuilder.array([
                this.formBuilder.group({
                  address: [null, [Validators.required]],
                  phone: [null, [Validators.required]]
                })
              ])
           });
       }

      initUserRow(): FormGroup {
            return this.formBuilder.group({
               address: [null, [Validators.required]],
               phone: [null, [Validators.required]],
        });
       }

       addUserRow(): void {
          const usersArray= 
             <FormArray>this.usersForm.controls['users'];
           usersArray.Push(this.initUserRow());
        }

       removeUserRow(rowIndex: number): void {
           const usersArray= <FormArray>this.usersForm.controls['users'];
           if (usersArray.length > 1) {
              usersArray.removeAt(rowIndex);
           } else {
            this.errorMessage = 'You cannot delete this row! form should contain at least one row!';
           setTimeout(() => {
             this.errorMessage = null;
           }, 4000);
         }
       }

 }

ビュー内:

<form *ngIf="usersForm" [formGroup]="usersForm" (ngSubmit)="createUsers()">
    <table class="table table-sm table-bordered">
            <thead>
              <tr class="text-center">
                <th>Address</th>
                <th>Phone</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody formArrayName="users">
              <tr *ngFor="let item of usersForm.controls.users.controls; let $index=index" [formGroupName]="$index">
                <td style="min-width: 120px">
                      <input class="form-control" type="text" formControlName="address"/>
                      <div class="text-danger" *ngIf="usersForm.controls['users'].controls[$index].controls['address'].touched
                         && usersForm.controls['users'].controls[$index].controls['address'].hasError('required')">
                        Please enter address!
                      </div>
                </td>

                <td style="min-width: 120px">
                      <input class="form-control" type="text" formControlName="address"/>
                      <div class="text-danger" *ngIf="usersForm.controls['users'].controls[$index].controls['phone'].touched
                         && usersForm.controls['users'].controls[$index].controls['phone'].hasError('required')">
                        Please enter phone number!
                      </div>
                </td>

                <td style="width: 100px">
                  <button (click)="addUserRow()" class="btn btn-success btn-sm mr-1" type="button"><i class="fa fa-plus"></i></button>
                  <button (click)="removeUserRow($index)" class="btn btn-danger btn-sm" type="button"><i class="fa fa-times"></i></button>
                </td>
              </tr>
            </tbody>
          </table>
</form>

今あなたの問題が解決されることを願っています!

3
TanvirArjel

リアクティブフォームでは、コードにフォームデータを保持するデータ構造を定義します。あなたの例では、this.form。ただし、フォーム定義には1つの住所コントロールと1つの電話コントロールしかありません。したがって、Angularに1つのアドレスと1つの電話のみを保存するように指示しました。

複数のアドレス/電話セットを許可するには、@ DavidZで言及されているFormArrayが必要です。その名前が示すように、FormArrayはフォーム値の配列を持つことを可能にします。

この例では、FormArrayは、ユーザーごとに1つのエントリを持つFormGroupで構成されます。 FormGroupは、FormControlのセット(アドレスと電話)で構成されます。

フォームコンポーネント

この例には、名前とアドレスの配列がありますが、一般的な考え方がわかるはずです。

ngOnInit(): void {
    this.customerForm = this.fb.group({
        name: ['', [Validators.required, Validators.minLength(3)]],
        addresses: this.fb.array([this.buildAddress()])
    });
}

buildAddress(): FormGroup {
    return this.fb.group({
            addressType: 'home',
            street1: ['', Validators.required],
            street2: '',
            city: '',
            state: '',
            Zip: ''
    });
}

このための完全なコードはここにあります: https://github.com/DeborahK/Angular2-ReactiveForms/tree/master/Demo-Final-Updated

2
DeborahK

FormArrayを使用できます この記事 はいい要約を与えます。

また、FormArrayFormGroupの間の differences を必ず理解してください。

0
DavidZ