【问题标题】:How to use reactive forms within ngFor如何在 ngFor 中使用响应式表单
【发布时间】:2019-01-04 17:18:45
【问题描述】:

用户数组可以有多个元素(用户)。在模板中,我遍历这个数组并为每个元素添加一个表单。现在每个表单都绑定到相同的表单组值。如果我为第一个用户填写表单,所有表单的提交按钮都会启用。如何将每个表单指向唯一的 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>

【问题讨论】:

    标签: angular angular-reactive-forms reactive-forms


    【解决方案1】:

    要解决您的问题,您必须使用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>
    

    希望现在您的问题将得到解决!

    【讨论】:

      【解决方案2】:

      使用响应式表单,您可以定义数据结构以在代码中保存表单数据。在您的示例中,您使用this.form 定义它。但是您的表单定义只有一个地址控件和一个电话控件。所以你告诉 Angular 只存储一个地址和一个电话。

      要允许多个地址/电话集,您需要 @DavidZ 提到的 FormArray。顾名思义,FormArray 允许您拥有一个表单值数组。

      在您的示例中,您的 FormArray 将由一个 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

      【讨论】:

        【解决方案3】:

        您可以使用FormArraythis article 给出了很好的总结。

        还要确保您了解FormArrayFormGroup 之间的differences

        【讨论】:

          猜你喜欢
          • 2019-02-22
          • 2019-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-12
          • 1970-01-01
          • 2018-10-10
          • 1970-01-01
          相关资源
          最近更新 更多