Angular *ngFor 与 ngModel 使用 Select 具有意外绑定
Angular *ngFor with ngModel using Select has unexpected binding
我正在尝试为建筑行业的用户创建一个动态表单,它将按层分析建筑物(任意层数)的输入:
最初向用户显示一层表单的表单,但可以选择添加额外的楼层:
我们应该能够添加任意数量的额外楼层,并根据需要删除特定楼层。
方法
为了实现这一点,我试图利用 *ngFor 并迭代一个将接收数据的数组,使用 ngModel 绑定到数组中的每个对象。
component.html
<form *ngFor = "let storey of storeyData; let i = index; trackBy: trackByFn(i)">
<md-select placeholder="Floor type" name ="floorTypeSelector{{i}}" [(ngModel)]="storeyData[i].floorTypes[0]">
<md-option *ngFor="let floorType of floorTypes" [value]="floorType.value">
{{floorType.viewValue}}
</md-option>
</md-select>
<button md-raised-button (click)="incrementStoreyNumber()">
<md-icon>library_add</md-icon>
Add storey
</button>
component.ts
export class FloorDetailsFormComponent implements OnInit {
selectedFloorType = [];
floorTypes = [
{value: 'concreteSlab', viewValue: 'Concrete slab'},
{value: 'suspendedTimber', viewValue: 'Suspended timber'},
{value: 'suspendedSlab', viewValue: 'Suspended slab'},
{value: 'wafflePod', viewValue: 'Waffle pod'}
];
storeyData = [{floorTypes: [],floorAreas:[] }];
storeyDataTemplate = {floorTypes: [], floorAreas:[]};
incrementStoreyNumber(){
this.storeyData.push(this.storeyDataTemplate);
}
trackByFn(index){
return index;
}
constructor() { }
ngOnInit() {
}
问题
似乎前两层正确地绑定到它们的变量,但是更改任何第 2 层到第 n 层的选定值将更改所有其他层(第一层除外)。
在搜索了其他类似问题的帖子后,我仍然不知道为什么会发生这种情况。其他人遇到的一个问题是,在 *ngFor 循环的每次迭代中都没有区分元素的名称,但是查看我的 console.log,我可以看到每个元素的名称都按应有的方式被索引。
我看到的一件有趣的事情是,如果我在 typescript 文件中将 storeyData 数组扩展到 n 层的长度,所有层数最多为 n 的都按照它们应该的方式绑定到它们自己的独立变量,并且所有层数后面添加的n+1个也有同样的问题。
我试过使用 trackBy 功能,但我似乎也无法使用它。当我试图即时扩展 *ngFor 范围时,我真的不了解幕后发生的事情。也许这只是不好的做法?如果你能在这里帮助我,我将非常感激(即使它 "hey, read up on this")
问题出在这一行:
this.storeyData.push(this.storeyDataTemplate);
当您将 storeyDataTemplate 添加到 storeyData 时,每次推送时都会绑定同一个对象,而 ngFor 会跟踪同一个对象。如果您更改为:
this.storeyData.push({floorTypes: [], floorAreas:[]});
它会起作用。
我正在尝试为建筑行业的用户创建一个动态表单,它将按层分析建筑物(任意层数)的输入:
最初向用户显示一层表单的表单,但可以选择添加额外的楼层:
我们应该能够添加任意数量的额外楼层,并根据需要删除特定楼层。
方法
为了实现这一点,我试图利用 *ngFor 并迭代一个将接收数据的数组,使用 ngModel 绑定到数组中的每个对象。
component.html
<form *ngFor = "let storey of storeyData; let i = index; trackBy: trackByFn(i)">
<md-select placeholder="Floor type" name ="floorTypeSelector{{i}}" [(ngModel)]="storeyData[i].floorTypes[0]">
<md-option *ngFor="let floorType of floorTypes" [value]="floorType.value">
{{floorType.viewValue}}
</md-option>
</md-select>
<button md-raised-button (click)="incrementStoreyNumber()">
<md-icon>library_add</md-icon>
Add storey
</button>
component.ts
export class FloorDetailsFormComponent implements OnInit {
selectedFloorType = [];
floorTypes = [
{value: 'concreteSlab', viewValue: 'Concrete slab'},
{value: 'suspendedTimber', viewValue: 'Suspended timber'},
{value: 'suspendedSlab', viewValue: 'Suspended slab'},
{value: 'wafflePod', viewValue: 'Waffle pod'}
];
storeyData = [{floorTypes: [],floorAreas:[] }];
storeyDataTemplate = {floorTypes: [], floorAreas:[]};
incrementStoreyNumber(){
this.storeyData.push(this.storeyDataTemplate);
}
trackByFn(index){
return index;
}
constructor() { }
ngOnInit() {
}
问题
似乎前两层正确地绑定到它们的变量,但是更改任何第 2 层到第 n 层的选定值将更改所有其他层(第一层除外)。
在搜索了其他类似问题的帖子后,我仍然不知道为什么会发生这种情况。其他人遇到的一个问题是,在 *ngFor 循环的每次迭代中都没有区分元素的名称,但是查看我的 console.log,我可以看到每个元素的名称都按应有的方式被索引。
我看到的一件有趣的事情是,如果我在 typescript 文件中将 storeyData 数组扩展到 n 层的长度,所有层数最多为 n 的都按照它们应该的方式绑定到它们自己的独立变量,并且所有层数后面添加的n+1个也有同样的问题。
我试过使用 trackBy 功能,但我似乎也无法使用它。当我试图即时扩展 *ngFor 范围时,我真的不了解幕后发生的事情。也许这只是不好的做法?如果你能在这里帮助我,我将非常感激(即使它 "hey, read up on this")
问题出在这一行:
this.storeyData.push(this.storeyDataTemplate);
当您将 storeyDataTemplate 添加到 storeyData 时,每次推送时都会绑定同一个对象,而 ngFor 会跟踪同一个对象。如果您更改为:
this.storeyData.push({floorTypes: [], floorAreas:[]});
它会起作用。