use*_*580 3 angular-material angular
在以下场景中我遇到了奇怪的行为。选择集合允许您配置myCars从可用汽车列表中选择的汽车列表 ( )。
<div *ngFor="let car of myCars; let i = index;">
<mat-form-field>
<mat-label>Car</mat-label>
<mat-select [(value)]="myCars[i]" (selectionChange)="selectionChanged($event, i)">
<mat-option>-</mat-option>
<mat-option *ngFor="let car of carsAvailable" [value]="car">{{car.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<button mat-raised-button color="primary" type="button" (click)="addNewCar()">Add new car</button>
Run Code Online (Sandbox Code Playgroud)
问题是,当我的列表中有两辆车时,例如:
Select1 : Ferrari
Select2 : Ferrari
Run Code Online (Sandbox Code Playgroud)
并将 的值更改Select1为Audi,两个选择都错误地设置为该值:
Select1 : Audi
Select2 : Audi
Run Code Online (Sandbox Code Playgroud)
但是 myCars 数组包含[Ferrari, Audi],这是正确的。有趣的是,如果我选择奥迪select2,select1则将保持不变。即使我有 10 个相同的选择,其中选择了 Ferrari,并将第 i 个选择更改为 Audi,也只有第 i+1 个选择会更改为 Audi。
你们中有人能解释为什么会发生这种情况吗?对我来说,这看起来像是某种竞争条件,其中与第 i 个选择对应的 DOM 项首先被删除,并且 Angular 设置第 i+1 个选择,因为它通过对象引用匹配它。
这是问题的示例: https://stackblitz.com/edit/angular-74wwjj ?file=app%2Fselect-value-binding-example.ts
当前行为的原因:
最初考虑您的列表为:
1. Ferrari
2. Ferrari
3. Ferrari
Run Code Online (Sandbox Code Playgroud)
这里提到1、2、3指标只是为了说明目的。实际上它们是相同的对象。
现在,当您将第一个下拉列表更改为 时Audi,新列表将变为:
Audi
1. Ferrari
2. Ferrari
Run Code Online (Sandbox Code Playgroud)
下表解释了为什么它会变成这样而不是下面。
Audi
2. Ferrari
3. Ferrari
Run Code Online (Sandbox Code Playgroud)
内部角度维护项目的链接列表。因此,在下表中提到了新列表项的下一个和上一个链接。要理解该表,请逐行阅读。虽然在实际代码中链表更改和 DOM 更新是分开发生的,但为了简单起见,我将它们合并在下面的解释中。
Old List | New List | New List prev | New List next | Description
1.Ferrari | Audi | null | 1.Ferrari | As Audi is new object, it will create new DOM node for this item and attaches it at 0 index. It will detach the 1.Ferrari object from index: 0.
2.Ferrari | 1.Ferrari | Audi | 2.Ferrari | It first checks if Ferrari object exists in detached list. In this case it does exist. So, it will re-attach the detached 1.Ferrari object at index: 1
3.Ferrari | 2.Ferrari | 1.Ferrari | 3.Ferrari | It checks if Ferrari exists in detached list. In this case it doesn't. So, it will attach the 2.Ferrari at index: 2.
Run Code Online (Sandbox Code Playgroud)
现在,列表中最后一项 (2.Ferrari) 的下一项是 3.Ferrari。由于新列表的长度应为 3,因此它将截断列表并丢弃 3.Ferrari。
因此,如果您再次检查您共享的演示,您会发现当我们更改第一个下拉列表的值时,感觉焦点转移到了第二项。感觉是这样,因为它实际上只是将我们的第一个项目 DOM 移动到第二个位置。由于它只是移动该记录并且没有对该项目进行任何更改检测,因此第二个下拉列表下方的显示值仍然显示 Ferrari。
解决方案:
您可以通过设置trackBy功能来解决这个问题。因此,它可以通过函数的返回值来跟踪,而不是通过对象引用来跟踪项目trackBy。在下面的示例中,它按索引跟踪项目。
<div *ngFor="let car of myCars; let i = index; trackBy: trackByIndex">
</div>
Run Code Online (Sandbox Code Playgroud)
trackByIndex(index, item) {
return index;
}
Run Code Online (Sandbox Code Playgroud)
工作示例:https://stackblitz.com/edit/angular-74wwjj-olzks2
希望它会有所帮助!
| 归档时间: |
|
| 查看次数: |
1654 次 |
| 最近记录: |