【问题标题】:Angular *ngFor with ngModel using Select has unexpected bindingAngular *ngFor 与 ngModel 使用 Select 具有意外绑定
【发布时间】:2018-03-21 09:07:33
【问题描述】:

我正在尝试为建筑行业的用户创建一个动态表单,它将按每层分析建筑物(任意层数)的输入:

  1. 最初向用户显示的是单层表单,但可以选择添加额外的楼层:

  2. 我们应该能够添加任意数量的额外楼层,并在需要时删除特定楼层。

方法

为了实现这一点,我尝试利用 *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> 

组件.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 范围时,我真的缺乏对引擎盖下发生的事情的理解。也许这只是不好的做法?如果你能在这里帮助我,我将非常感激(即使它是“嘿,请阅读 this”)

【问题讨论】:

  • 在这里查看我的答案,我认为这是您问题的解决方案:stackoverflow.com/questions/41265761/…
  • 非常感谢 Stefan 的回复。表单组的背景信息很有趣。我切换到使用 [ngModelOptions]="{standalone: true}",并按照链接解决方案中的建议删除了 name 属性,但是它仍然表现出相同的行为。这是我之前尝试过但没有取得多大成功的建议解决方案之一。
  • 也在第二个 ngfor 上实现 trackby。并将其更改为无参数版本: trackBy: trackByFn 和 trackByFn(item, index){return index}
  • 非常感谢维加。该行为将适合一个实例,其中选择元素没有相互区分,因此输入被覆盖,所以这是一个好主意。我还没有时间实施你的解决方案,但我会在第二天左右告诉你它的进展情况:)
  • 嗨@Vega,我发现第二个ngFor循环上的trackBy函数在这种情况下没有帮助。为了调试,在添加它之后,我将 ngModel 变量绑定到一个空数组,并在每次单击“添加楼层”按钮时将另一个空数组推到它上面。有趣的是,所有数据都正确保存,并且选择字段没有相互覆盖。然后,我按函数删除了 both 跟踪并观察到相同的行为:/ 我觉得这表明我处理数据的方式存在一些更根本的问题。这个实现并不理想,所以我会再玩一玩:)

标签: javascript arrays angular angular-ngmodel ngfor


【解决方案1】:

问题出在这一行:

this.storeyData.push(this.storeyDataTemplate);

当您将 storeyDataTemplate 添加到 storeyData 时,每次推送时都会绑定同一个对象,并且 ngFor 会跟踪同一个对象。如果您更改为:

this.storeyData.push({floorTypes: [], floorAreas:[]});

它会起作用的。

DEMO

【讨论】:

  • 就是这样!你是个天才 :) 非常感谢你花时间来理解这个问题。该修复解释了我所看到的所有行为,并让我对 ngFor 的工作原理有了一些额外的了解。只要我有足够的声誉(我只有 8 名……),我就会满怀热情地投票 :)
猜你喜欢
  • 2017-03-11
  • 2023-03-27
  • 2019-07-08
  • 2018-11-11
  • 2018-09-24
  • 2016-07-27
  • 1970-01-01
相关资源
最近更新 更多