我有一个模板绑定到observableArray
<ul data-bind="template: { name: 'defaultTemplate', foreach: itemsArray}"></ul>
...
我需要通过点击链接每次刷新数据
<a data-bind="click: LoadData"><span>Refresh</span></a>
我的viewModel的第一个版本:
function viewModel (){
this.itmesArray = ko.observableArray([]);
self = this;
this.LoadData(){
if('undefined' != typeof MusicArray )
self.itmesArray.removeAll();
LoadDataFromServerAsync(self.itmesArray);
}
//ini
LoadData();
...
}
但问题是数据是从异步中的服务器加载的,所以当我用很少的时间间隔快速点击链接时,数据可能会在我的obeservable数组中重复多次。 所以我认为我需要在每次刷新时将数据加载到新数组。
然后是viewModel的第二个版本:
function viewModel (){
this.itmesArray = ko.observableArray([]);
self = this;
this.LoadData(){
if('undefined' != typeof MusicArray )
self.itmesArray.removeAll();
var tempArray = new Array();
LoadDataFromServerAsync(tempArray);
self.itmesArray(tempArray);
}
//ini
LoadData();
...
}
而新的问题是UI无法感知数组的变化,似乎 self.itmesArray(tempArray)将构造一个新的observableArray对象,但模板绑定仍然是跟踪旧的observableArray对象,我不确定这个。 所以我想知道如何通知我的阵列已更改的模板/ ui绑定,或者是否还有其他解决方法来解决我的问题?
已添加:jsFiddle上的代码http://jsfiddle.net/zzcJC/10/
答案 0 :(得分:1)
你可以像Gene建议的那样做。为了在客户端执行所有操作,您可以创建一个辅助对象来封装逻辑:它触发请求,获取响应,有一个“中止”方法来停止请求(如果用户在等待数据时按“刷新”) ),并仅在所有数据到达时更新viewmodel。
我创建了一个jsFiddle:http://jsfiddle.net/saurus/dE6S9/
这使用“setTimeout()”来模拟ajax调用,将超时ID存储在一个数组上(你将存储由ajax调用返回的xhr),并调用“cancelTimeout()”来中止调用(你将使用“xhr” .abort或类似的。)
答案 1 :(得分:0)
如果要以异步模式加载数据,问题可能就是行
self.itmesArray(tempArray);
在
之前执行LoadDataFromServerAsync(tempArray);
已完成从服务器加载新数据,因此它会保持绑定空数组。
要修复它,您应该在服务器返回新数据后执行绑定。例如,使用jquery进行ajax调用,您应该在“success”回调中更新viewmodel。我是这样做的:
$.ajax({
type: "POST",
url: "ws.asmx/GetData",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
processData: false,
success: function(msg) {
viewModel.itmesArray(msg);
}
});
如果这对您没有帮助,我认为我们需要查看'LoadDataFromServerAsync'实现。
答案 2 :(得分:0)
所以,如果我理解正确,你想点击“刷新”,这会触发一些ajax调用,从这些调用返回的数据完全替换旧数据。
一种方法是不确定每个呼叫是否独立地为其他呼叫工作。例如,我在评论中快速建议做一些事情:将每个调用分开,当单个调用返回新数据时,从数组中删除旧数据并添加新数据。这假设您可以区分不同调用返回的元素。
另一种方法是完全避免多次调用,你可以阻止UI交互直到完成(例如使用jquery blockui插件或类似的东西),或者如果你想让用户在你更新时继续使用界面它,你可以简单地避免在有些人还在飞行中时发出新请求。
这两种方式都需要知道请求序列何时开始,但这很容易:这种情况发生在“LoadData”方法的开头。知道完成所有请求的时间有点复杂,也许有更好的方法,如果没有,你可以创建一个计数器,为你发出的每个ajax请求递增1,然后,对于每个完成的请求,“推送”新数据在observableArray上,并递减计数器(在jquery中我将使用“完整”回调,因为即使出现错误也可以被调用)。在“LoadData”的最开始(甚至在清除数组之前)添加一个测试:
if (counter > 0) return;
如果你使用“blockui”方式,你应该在减去它之后检查每个“完整”回调中的计数器,如果它为零则是时候取消阻止UI(“blockui”选项需要一些工作来避免做UI事情在viewModel)。
除非我还缺少某些东西......
答案 3 :(得分:0)
也许处理重叠请求的一种方法是在客户端中保留用户操作计数器,并将该值传递给服务器,假设您可以控制服务器发回的内容。然后,您可以忽略具有过期用户操作值的响应。如果您无权访问服务器数据,则仍可以通过将操作计数器值粘贴到成功处理程序中来使用此方法。这是这段代码的草图。 (警告:未经测试)
function viewModel() {
var self = this;
var actionCounter = 0;
var items = ko.observableArray([]);
// This is triggered by a user request
this.handleUserAction = function() {
self.clearData();
self.loadData(0, ++actionCounter); // assume 0=root
}
this.clearData = function() {
this.items.removeAll();
}
// return some handle of the next request, or null
this.moreRequestsRequired = function(data) {
...
return ...;
}
this.processData = function(data, reqNo) {
// this is where you would append it to the array
...
// this is where the recursive call could be made
var handle = self.moreRequestsRequired(data);
if (handle)
loadData(handle, reqNo);
}
this.loadData = function(handle, n) {
var reqNumber = n;
$.ajax('server/request', {
data: {dir: handle},
success: function(data) {
if (reqNumber == actionCounter)
processData(data);
}
});
}
};