我最近注意到一些关于使用KO映射插件更新页面数据的事情。我相信的第一个现在已在2.1.1中修复,下面显示的第二个仍然存在:
我有一个简单的模型。问题在于它包含的地址数组。当我使用映射插件时,它似乎跟踪数组中的2个元素,而实际上只有一个元素。我不确定这是我的代码或映射插件的问题。请考虑以下简单示例:
//Retrieved thru AJAX
var serverData = { name: "Bob", Addresses: [{ AddressLine: "", City: "", PostalCode: "", StateID: 10}] };
load(serverData);
//Seems OK at this point
//this.vm.__ko_mapping__.mappedProperties shows properties for Addresses[0] & name which makes sense
//Now some time goes by and we want to update the bound VM w/ new data from the server
load(serverData);
//Problem!
//this.vm.__ko_mapping__.mappedProperties shows properties for Addresses[0] & Addresses[1]
//But there is no Addresses[1]!!
//Lets simulate an update of data (1 more time)
load(serverData);
//Interestingly it doesn't get any worse, still just Addresses[0] & Addresses[1]
function load(d)
{
if (this.vm) //Refresh existing VM
{
ko.mapping.fromJS(serverData, vm);
}
else //On 1st Load have mapping create the VM and bind it
{
this.vm = ko.mapping.fromJS(serverData); //Mapping creates object from server data
ko.applyBindings(this.vm, $("body")[0]);
}
}
答案 0 :(得分:2)
映射插件允许定义一个返回数组中元素的键的回调。 (请参阅http://knockoutjs.com/documentation/plugins-mapping.html处的“使用键唯一标识对象”)。这用于确定对象是新对象还是旧对象。有三种可能的状态:新对象添加到数组,数组中已存在的元素保留(但会更新)或现有元素已从数组中删除,因为它不再出现在新数据集中。 (这些状态实际上由实用函数ko.utils.compareArrays确定)
这里正确的状态是“保留”,但由于你没有为数组中的地址提供唯一键,映射插件不知道那些条目实际上是相同的 - 因此状态“remove”得到分配给当前对象和状态“添加”到新对象。
这导致列表中包含需要注意的所有元素 - 当前的键具有键“0”,新的键为“1”,因此“mappedProperties”中的奇怪条目。我认为这可以被视为一个错误,但这是一个非常棘手的问题。并且它不是真正的内存泄漏,因为ghost条目的数量始终为numPreviousEntries
。
这是一个小提示,证明使用唯一键(如果你没有多行,可以是任何东西,所以我使用了状态id)确实解决了这个问题:http://jsfiddle.net/xTHFg/4/