如何在 angular 中创建表单数组?

How can I create an array of forms in angular?

我想为分数中数组的每个元素创建并绑定一个 formControl

我尝试这样做,但出现控制台错误:
找不到路径为:'crime_types -> 0
的控件 找不到带有路径的控件:'crime_types -> 1 -> score'

 public resultsForm: FormGroup;

 constructor(
    private _formBuilder: FormBuilder,
  ) {
      this.resultsForm = this._formBuilder.group({
      crime_types: this._formBuilder.array([])
    });

     for (let i = 0; i < this.tasks.length; i++) {
      this.formArrayCrimeType.push(
        this._formBuilder.group({
          psychological_tasks_id: new FormControl(this.tasks[i].id),
          patients_id: new FormControl(this.patientId),
          score: new FormControl('', [Validators.required]),
        })
      );
    }
   }

    public get formArrayCrimeType(): FormArray {
    return this.resultsForm.get("crime_types") as FormArray;
  }

    public getNumber(): number {
    this.numb = this.numb + 1;
    return this.numb;
  }
 

模板

<ng-container formArrayName="crime_types">
    <ng-container *ngFor="let task of tasks" [formGroupName]="getNumber()">
        <div *ngIf="task.psychological_processes_id == process.id" class="col-12 col-md-6">
            <div class="form-div">
                <label for="gender" class="form-tag">{{task.description}} *</label>
                <select formControlName="score" class="custom-select" required>
                    <option selected disabled value="">Seleccionar puntaje...</option>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">2</option>
                </select>
            </div>
        </div>
    </ng-container>
</ng-container>

当我们有一个 FormGroups 的 FormArray 时,通常我们使用 getter

get formArray()
{
   return this.form.get('arrayName') as FormArray
}

还有我们的.html喜欢

<form [formGroup]="form">
   <div formArrayName="arrayName">
     <div *ngFor="let group of formArray.controls;let i=index"
           [formGroupName]="i">
           ..here we are inside the formGroup, so use formControlName..
            <input formControlName="prop1">
     </div>
   </div>
</form>

“关键”总是要有一个formGroup,并且在里面使用formControlName。在 FormGroup 中的典型 fromArray 中,我们使用 formArrayName[fromGroupName]="i".

但是假设您有一个 FormArrays 的 FormArray。这管理一个数据,如

arrayName:[
  [{row:1,col:1},{row:1,col2}]
  [{row:2,col:1},{row:2,col2}]
]

要获取内部 FormArray,我们需要一个函数(我们不能使用 getter),例如

getInsideArrayForm(index:number)
{
    return this.formArray.at(index) as FormArray
}

还有一个获取formGroup

getInsideFormGroup(i:number,j:number)
{
    return this.getInsideArrayForm(i).at(j) as FormGroup
}

看看我们如何使用之前声明的函数

然后我们可以使用

<form [formGroup]="form">
  <ng-container formArrayName="arrayName">
    <!--see we iterate first over outher formArray.controls-->
    <ng-container *ngFor="let array of formArray.controls;
           let i=index">

       <!--see how we use to loop the function 
     "getInsideArrayForm" and how we indicate "formGroup" using 
     the function getInsideFormGroup-->
       <ng-container *ngFor="let group of getInsideArrayForm(i).controls;
                let j=index" [formGroup]="getInsideFormGroup(i,j)>

            ..here we are inside the FormGroup..
            <input formControlName="row">
            <input formControlName="col">
       </ng-container>
    <ng-container>
  </ng-container>
</form>

注意:我使用 FormArrays 的 FormArray,以及 FormGroup 中的第一个 FormArray,没有人强迫我们使用 FormGroup。我们可以直接使用 FormArray 来管理数据,例如

[
  [{row:1,col:1},{row:1,col2}]
  [{row:2,col:1},{row:2,col2}]
]

只是,记住获取FormGroup是必要的,但是我们可以去掉“

<ng-container *ngFor="let array of formArray.controls;
       let i=index">
   <ng-container *ngFor="let group of getInsideArrayForm(i).controls;
            let j=index" [formGroup]="getInsideFormGroup(i,j)>

        ..here we are inside the FormGroup..
        <input formControlName="row">
        <input formControlName="col">
   </ng-container>
<ng-container>

(*) 在 Angular 8 中我们可以迭代循环的变量,但在 Angular 9 和 next

中不行

在我们的例子中,我们有一个“简单的”FormGroups 的 formArray。 “难”的是formArray是按tab分割的,但是“结构”总是一样的

我在重要的部分写了评论.html

    <div class="section">
      <div class="section__content container__shadow mx-3">
        <h2 class="section__title">
          {{ test.description }} <span> <i class="bx bx-test-tube"></i></span>
        </h2>
    
        <!--here declare the [formGroup]="resultForms"-->
        <form *ngIf="resultsForm" autocomplete="off" [formGroup]="resultsForm">
    
          <!--and create a div with formArrayName-->
          <div formArrayName="results">
    
            <mat-tab-group mat-align-tabs="center" #matGroup>
              <mat-tab
                *ngFor="let process of processes; let i = index"
                label="{{ process.description }}"
              >
                <div class="text-center col-md-12" style="overflow: hidden;">
                  <h2 class="section__subtitle">{{ process.description }}</h2>
                  <div class="row">
                    <ng-container>
    
                      <!--instead iterate over tasks, we iterate 
                          over formArray.controls
                          NOT over tasks (let task of tasks)
                      -->
                      <ng-container
                        *ngFor="let group of formArray.controls; 
                                          let i = index"
                      >
    
                        <!--and we use [formGroupName]="i"
                          I put in another div because we use this div to
                          show or not is "tasks[i]==process.id"
                        -->
                        
                        <div
                          [formGroupName]="i"
                          *ngIf="tasks[i].psychological_processes_id==process.id"
                          class="col-12 col-md-6"
                        >
                          <div class="form-div">
    
                           <!--we use tasks[i].description-->
                            <label for="gender" class="form-tag"
                              >{{ tasks[i].description }} *</label
                            >
    
                            <!--in select we use formControlName="score"-->
                            <select
                              class="custom-select"
                              formControlName="score"
                              required
                            >
    
                              <!--see how you indicate that you should
                                  "Seleccionar puntaje", the [value]="null"
                                  makes that works the Validators.required
                                  but when create the formControl we need use
                            score: new FormControl(null, [Validators.required]),
                              -->
                              <option selected hidden disabled [value]="null">
                                Seleccionar puntaje...
                              </option>
    
                              <!-- use [ngValue] (not only value) 
                                   if we want to get a number, 
                                   else we get a string-->
                              <option [ngValue]="1">1</option>
                              <option [ngValue]="2">2</option>
                              <option [ngValue]="3">3</option>
                            </select>
                          </div>
                        </div>
                      </ng-container>
                    </ng-container>
                  </div>
                  ...button next...
                  ...button save...
    
                </div>
              </mat-tab>
            </mat-tab-group>
          </div>
        </form>
      </div>
    </div>

forked stackblitz