当使用Angular CDK DnD使用地图时,如何更新视图?



我有一个小列表,其中有一些项目可以重新排序(参见stackblitz)。在内部,该列表是作为映射实现的。方便的是,Angular提供了管道keyvalue,它允许像这样简单地迭代映射:

*ngFor="let item of doc.items | keyvalue:sortHash"

您可以提供一个函数sortHash,它负责对列表进行排序。我想用cdkDropList,以便给列表提供nd排序。这在使用数组时是微不足道的:

(cdkDropListDropped)="dropItem($event, doc.items, doc)

您必须简单地将一个函数传递给cdkDropListDropped,该函数将负责在数组中移动项。Angular提供了一个内置函数moveItemInArray:

import { moveItemInArray } from '@angular/cdk/drag-drop';
...
async dropItem(event: CdkDragDrop<string[]>, list: any, doc: any) {
moveItemInArray(list, event.previousIndex, event.currentIndex);
}

这在数组中可以正常工作,但在我的情况下,我依赖于映射,其中顺序由属性"order"定义,请参阅我的数据结构:

doc = {
meta: {
text: 'title',
...
},
items: {
SEC_000000: {
meta: {
text: 'Episode I - The Phantom Menace',
order: '0',
...
},
},
SEC_111111: {
meta: {
text: 'Episode II - Attack of the Clones',
order: '1',
...
},
},
SEC_222222: {
meta: {
text: 'Episode III - Revenge of the Sith',
order: '2',
...
},
},
},
};

因此我的dropItem函数有点不同,它

  1. 将我的地图(doc.items)转换为数组
  2. 然后使用内置的moveItemInArray函数有效地移动数组内的项目
  3. 则更新"订单";属性,最后是
  4. 将数组转换回地图

排序功能按预期工作,但当免打扰时UI不更新。

下面是一个简化的stackblitz示例代码。我遗漏了什么?

答案就在Angular的核心深处。您正在使用KeyValuePipe。源。

我们感兴趣的部分是:

const differChanges: KeyValueChanges<K, V>|null = this.differ.diff(input as any);
const compareFnChanged = compareFn !== this.compareFn;
if (differChanges || compareFnChanged) {
this.keyValues.sort(compareFn);
this.compareFn = compareFn;
}

如果在输入对象中发现了差异,则运行排序函数。

您可以控制日志differChanges,并看到它在视图初始化后始终返回null。为什么?我们需要查看不同的代码:

// Add the record or a given key to the list of changes only when the value has actually changed
private _maybeAddToChanges(record: KeyValueChangeRecord_<K, V>, newValue: any): void {
if (!Object.is(newValue, record.currentValue)) {
record.previousValue = record.currentValue;
record.currentValue = newValue;
this._addToChanges(record);
}
}

不同之处在于使用Object.is(newValue, record.currentValue)来确定值是否已更改。在这种情况下,要区分的对象的值是对象本身,并且Object.is()不计算深度相等。

所以你至少有两个选择:

  • 写你自己的键值管道,以你想要的方式工作。
  • 使用不同的数据结构来保存电影信息

我已经创建了一个工作StackBlitz自定义暴力破解策略keyvalue管道。

最新更新