无法在响应式表单的 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;...
因此不正确。
解决方案
因此模板应如下所示:
<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>
我认为这可能是 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;...
因此不正确。
解决方案
因此模板应如下所示:
<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>