无法在响应式表单的 FormArray 中为 FormArray 输入超过 1 个字符

Unable to typing more than 1 character in input for FormArray within a FormArray for Reactive Forms

我认为这可能是 Reactive Form 的一个错误。如果有经验丰富的 Angular 专家提供任何帮助,我将不胜感激。

问题现象:无法在给定时间输入超过 1 个字符。

发生:当输入是 FormArray 中的 FormArray 时

我添加了一个 Plunker link,如下所示: https://embed.plnkr.co/zl2BQe/.

//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
 })
export class AppModule { }

//app.component.ts
import { Component, OnInit} from '@angular/core';
import { FormArray, FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  testForm: FormGroup; 

  ngOnInit(){
   this.testForm = new FormGroup({
   'lines': new FormArray([
    new FormGroup({
      'fields': new FormArray([
        new FormControl('')
      ])
     })
    ])
   })
  }

onAddLine(){
if(this.testForm.value.lines.length<10){
  (<FormArray>this.testForm.get('lines')).push(
    new FormGroup({
      'fields': new FormArray([
        new FormControl()
      ])
     })
   )
 }
}

onAddField(){
  // Not developed       
 }
}

//app.component.html
<div class="panel panel-default">
  <div class="panel-heading">
    Angular Reactive FormArray Error 
    <!--<button class="btn btn-primary" (click)="onAddField()">Add 
    Field</button>-->
    <button class="btn btn-primary" (click)="onAddLine()">Add 
    Line</button>
  </div>
<div class="panel-body">
  <form [formGroup]="testForm">
    <div class="form-inline" *ngFor="let line of testForm.value.lines; let i = index" formArrayName="lines">
      <div class="form-group">
        <span [formGroupName]="i">
          <span *ngFor="let field of testForm.value.lines[0].fields; let j = index" formArrayName="fields">
              <input type="text" class="form-control" [formControlName]="j">
              Please Type on Input Field
          </span>
        </span>
      </div>
    </div>
  </form>
</div>

原因

您遇到此问题是因为您依赖 formGroup.value,它会在任何输入值更改时获取一个新实例。因此,您的控件树将在 DOM 中重新创建,从而失去焦点。

产生这个问题的步骤是:

  • 您将直接反映值的输入更改为 FormControl
  • formGroup.value 变化
  • *ngFor 迭代新值并创建新元素删除旧元素
  • 新元素将具有前一个元素值但没有焦点

为什么 *ngFor 创建新元素

NgFor 创建新元素是因为 trackBy 默认情况下是枚举值。如果该值发生变化,则由旧值跟踪的 DOM 中的元素被认为已过时,因此被删除,并为新值创建一个新元素。即使该值看起来相同,但实际上并非如此,它只是 FormControl 的另一个实例,因为您实际上是在 FormControl 上枚举。

你的情况: *ngFor="let line of testForm.value.lines;...*ngFor="let field of testForm.value.lines[0].fields;... 因此不正确。

解决方案

Here is an updated Plunker.

因此模板应如下所示:

  <div class="panel panel-default">
    <div class="panel-heading">
      Angular Reactive FormArray Error 
      <!--<button class="btn btn-primary" (click)="onAddField()">Add Field</button>-->
      <button class="btn btn-primary" (click)="onAddLine()">Add Line</button>
    </div>
    <div class="panel-body">
      <form [formGroup]="testForm">
        <div class="form-inline" *ngFor="let line of testForm.get('lines').controls; let i = index" formArrayName="lines">
          <div class="form-group">
            <span [formGroupName]="i">
              <span *ngFor="let field of line.get('fields').controls; let j = index" formArrayName="fields">
                  <input type="text" class="form-control" [formControlName]="j">
                  Please Type on Input Field
              </span>
            </span>
          </div>
        </div>
      </form>
    </div>
  </div>