gpt4 book ai didi

javascript - 在计算的观察器中聚合数组数据,但在KnockoutJS中保持状态

转载 作者:行者123 更新时间:2023-11-28 01:37:51 25 4
gpt4 key购买 nike

这是一个相当复杂的问题。我试图尽可能地将代码优化为仅显示问题所需的代码。这是一篇很长的文章-考虑一下自己!

在此jsFiddle上可以看到该问题的有效演示。



我想做的是基于数组中各项的公共属性将数组聚合为组。实际上,将数组聚合成组是很简单的:

function ViewModel() {
var self = this;

this.groupProperty = ko.observable('groupId');

this.data = ko.observableArray();
this.view = ko.computed(function () {
var i, element, value, grouped = {};

for (i = 0; i < self.data().length; i++) {
element = self.data()[i];

if (!element.hasOwnProperty(self.groupProperty()))
continue; //Exclude objects that don't have the grouping property...

value = ko.isObservable(element[self.groupProperty()]) ? element[self.groupProperty()]() : element[self.groupProperty];

if (!grouped.hasOwnProperty(value))
grouped[value] = new Group(value);

grouped[value].items().push(element);
}

return transformObjectIntoArray(grouped);
});
}


transformObjectIntoArray可以在jsFiddle示例中看到。它只是通过基本摆脱属性而将对象变成数组。

这需要像这样的数据数组:

[
Item { label: 'Item 1', groupId: 'A' },
Item { label: 'Item 2', groupId: 'A' },
Item { label: 'Item 1', groupId: 'B' },
Item { label: 'Item 2', groupId: 'B' }
]


将其变成以下对象:

{
'A': [
Item { label: 'Item 1', groupId: 'A' },
Item { label: 'Item 2', groupId: 'A' }
],
'B': [
Item { label: 'Item 1', groupId: 'B' },
Item { label: 'Item 2', groupId: 'B' }
]
}


然后将其转换为以下数组:

[
[
Item { label: 'Item 1', groupId: 'A' },
Item { label: 'Item 2', groupId: 'A' }
],
[
Item { label: 'Item 1', groupId: 'B' },
Item { label: 'Item 2', groupId: 'B' }
]
]


到目前为止,一切都按预期工作,如jsFiddle所示。

当我向数据数组添加新元素时,问题就开始了。在以下代码中, vm是我的 ViewModel实例

vm.data.push(new Item('Item X', 'A')); //Add a new item called 'Item X' to the 'A' group


您可能已经猜到了,这将导致计算的可观察的 view执行,从而重新聚合基础数据数组。将创建所有新的 Group对象,这意味着与它们关联的所有状态信息都将丢失。

这对我来说是个问题,因为我在 Group对象上存储了它们是否应该展开或折叠的状态:

function Group(label) {
this.expanded = ko.observable(false); //Expanded state is stored here
this.items = ko.observableArray();
this.label = ko.observable(label);
}


因此,由于它们被重新创建,因此状态信息将丢失。因此,所有组都还原为其默认状态(折叠)。



我知道我要面对的问题。但是,我正在努力提出一个并非难以解决的解决方案。我想到的可能解决方案包括:

维护组状态图

我的第一个想法是创建一个可用作地图的对象。它将使用groupId作为键名,状态将是值:

{
'A': GroupState { expanded: true },
'B': GroupState { expanded: false }
}


即使每次添加元素都会重新创建组,但 GroupState仍将保留。我无法解决的问题是如何从 GroupState映射中删除不再存在的组。

例如,

vm.data(someNewArray);


其中, someNewArray是由数组组成的项,没有与 GroupState映射中的当前项相对应的groupId。如何删除不再有参考的条目?这似乎是我的应用程序中的内存泄漏。

可以在 jsFiddle处看到这个问题。注意,单击按钮后,组状态大小将增加到5个元素,但只有3个组。这是因为即使不再使用原始的2个组,也不会将它们删除。

维护一个viewState数组并删除计算的observable

我的第二个想法是删除计算的可观察 view。取而代之的是,我有一个名为 viewState的第二个可观察数组,该数组将被聚合到当前“视图”中后成为 data数组。但是,我很快就遇到了这个想法的问题。

首先,我必须编写几个方法来维护两个数组之间的状态: add()remove()clear()等。考虑到必须这样做,我立即开始质疑是否有第二个数组一个好主意。

其次,删除计算所得的数组意味着线性搜索 viewState数组,以查看是否有任何当前元素包含与传入项目相似的groupId。在实践中,这将很快发展起来,我不喜欢在每个添加项( O(n) vs O(1))上迭代整个数组的理论。在将来,我可能正在处理数千个项目。



我觉得可能有一个简单的解决方案,但是我正在努力地努力。有没有人有任何想法可以解决此问题,或者知道使用KnockoutJS来实现这一目标的完全更好的方法?也许,我上面的想法之一可以使您获得更多的见解(我仍然觉得 GroupState地图在正确的轨道上)

如果我遗漏了一些关键信息,请告诉我,我会尽力添加。

最佳答案

那这个主张呢?


不要使用任何计算
在创建新项目的过程中,创建一个不存在的组并将其添加到该组中


注意:
我正在使用arrayFirst查找在创建项目期间是否存在一个组,它是O(n),但是您可以将组存储在属性中,以便查找应该是O(log(n))(未经测试)

function Item(label, groupId) {
var self = this;
self.label = ko.observable(label);
self.groupId = ko.observable(groupId);
}

function Group(label) {
var self = this;
self.expanded = ko.observable(false);
self.items = ko.observableArray();
self.label = ko.observable(label);

self.addItem = function(item) {
self.items.push(item);
}
}

function ViewModel() {
var self = this;

self.groups = ko.observableArray();

self.addItem = function(label, groupId) {
var group = ko.utils.arrayFirst(self.groups(), function(gr) {
return groupId == gr.label();
});

if(!group) {
console.log('not group');
group = self.addGroup(groupId);
}

var item = new Item(label, groupId);
group.addItem(item);
}

self.addGroup = function(groupId) {
var group = new Group(groupId);
this.groups.push(group);
return group;
}

this.buttonPressed = function () {
vm.addItem("Item X", "A");
};
}

var vm = new ViewModel();
ko.applyBindings(vm);

vm.addItem("Item 1", 'A');
vm.addItem("Item 2", 'A');
vm.addItem("Item 1", 'B');
vm.addItem("Item 2", 'B');


JSFiddle link

关于javascript - 在计算的观察器中聚合数组数据,但在KnockoutJS中保持状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21295079/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com