- 首页
- 其他开发
- 无法在响应式表单的 FormArray 内的 FormArray 输入中键入 1 个以上的字符
无法在响应式表单的 FormArray 内的 FormArray 输入中键入 1 个以上的字符
[英] Unable to typing more than 1 character in input for FormArray within a FormArray for Reactive Forms
本文介绍了无法在响应式表单的 FormArray 内的 FormArray 输入中键入 1 个以上的字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我认为这可能是 Reactive Form 的一个错误.如果能得到更有经验的 Angular 专家的帮助,我将不胜感激.
现象:在指定时间内无法输入超过 1 个字符.
出现:当输入是 FormArray 中的 FormArray 时
我已经包含了一个Plunker链接,如下所示:https://embed.plnkr.co/zl2BQe/.
//app.module.ts从'@angular/platform-browser' 导入 { BrowserModule };从'@angular/core' 导入 { NgModule };从'@angular/forms'导入{ReactiveFormsModule};从 './app.component' 导入 { AppComponent };@NgModule({声明: [应用组件],进口:[浏览器模块,响应式表单模块],提供者:[],引导程序:[AppComponent]})导出类 AppModule { }//app.component.ts从@angular/core"导入{组件,OnInit};导入 { FormArray, FormControl, FormGroup } from '@angular/forms';@成分({选择器:'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']})导出类 AppComponent 实现 OnInit {testForm:FormGroup;ngOnInit(){this.testForm = new FormGroup({'行':新的FormArray([新表单组({'字段':新的FormArray([new FormControl('')])})])})}onAddLine(){if(this.testForm.value.lines.length<10){(<FormArray>this.testForm.get('lines')).push(新表单组({'字段':新的FormArray([新的表单控件()])}))}}onAddField(){//未开发}}//app.component.html<div class="panel panel-default"><div class="panel-heading">Angular Reactive FormArray 错误<!--<button class="btn btn-primary" (click)="onAddField()">添加字段</button>--><button class="btn btn-primary" (click)="onAddLine()">添加线按钮>
<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">请在输入字段中输入</span></span>
</表单>
解决方案
原因
您遇到此问题是因为您依赖 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;...
由于这个原因是不正确的.
解决方案
这是一个更新的 Plunker.
因此模板应如下所示:
<div class="panel-heading">Angular Reactive FormArray 错误<!--<button class="btn btn-primary" (click)="onAddField()">添加字段</button>--><button class="btn btn-primary" (click)="onAddLine()">添加行</button>
<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">请在输入字段中输入</span></span>
</表单>
I am thinking this could be a bug for Reactive Form. I would appreciate any help from more experienced Angular Experts.
Symptom: Unable to key in more than 1 character in input at given time.
Occurrence: When input is a FormArray within a FormArray
I have included a Plunker link as below:
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>
解决方案
Cause
You get this problem because you rely on formGroup.value
which gets a new instance when any of the input value changes. Therefore your control tree will be recreated in DOM thus loosing the focus.
The steps which create this problem are:
- you change the input which reflect the value directly to the
FormControl
value
- the
formGroup.value
changes
*ngFor
iterates over the new value and creates new elements removing the old ones
- the new element will have the previous element value but not the focus
Why *ngFor creates new elements
NgFor
creates new elements because of trackBy
which is by default the enumerated value. If the value changes, the element from DOM, which is tracked by the older value, is considered to be obsolete, thus being removed, and a new element is created for the new value. Even if the value appears to be the same, it is not, is just another instance of FormControl
, as you are actually enumerating over the FormControl
s.
In your case:
*ngFor="let line of testForm.value.lines;...
and
*ngFor="let field of testForm.value.lines[0].fields;...
are incorrect for this reason.
Solution
Here is an updated Plunker.
Therefore the template should look like:
<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>
这篇关于无法在响应式表单的 FormArray 内的 FormArray 输入中键入 1 个以上的字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文