以下是一些复制问题的代码
places = ["London","Paris","Brussels"];
placeWikis = ko.observableArray([]);
var viewModel = function(){
for (i in places) {
function wikiInit(callback){
this.wikiMarkup = "";
var wikiTitle = places[i].replace(" ", "_");
var wikiURL = "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles="+places[i];
$.ajax({
type:"GET",
dataType:"jsonp",
async: false,
url: wikiURL,
success: function(result){
callback(result.query.pages[Object.keys(result.query.pages)[0]].extract);
},
error: function(){
}
});
};
wikiInit(function (wikiString) {
var wikiMarkup = "<h4>Wikipedia:</h4>" + "<p>" + wikiString + "</p>";
placeWikis.push(wikiMarkup);
console.log(placeWikis());
});
}
ko.applyBindings(new viewModel(), view);
问题是每次此代码运行并返回来自源的数据,在这种情况下,维基百科都会随机排序placesWikis()的结果。我将API结果分别添加到不同的<div>
,因此我需要将结果的索引与其各自条目的索引相同[]
答案 0 :(得分:1)
订购时遇到两个问题:
for.in
不保证订单; observableArray
,但无法保证它们会在你发射它们时到达!后者可能是最突出的问题。您当前push
会导致您的可观察数组,但您按浏览器返回结果的顺序执行此操作。
这是一个稍微复制一下你的问题的最小版本,不同的回调时间被夸大了:
// Mock Ajax stuff:
var $ = {
ajax: function(options) {
// Simulate unknown return moment with setTimeout:
setTimeout(function() {
options.success(options.url + " is a great city...");
}, Math.random() * 1500 + 50);
}
}
function ViewModel() {
var self = this;
self.items = ko.observableArray([]);
var places = ["london", "brussels", "paris"];
function wikiInit(place, callback) {
$.ajax({
url: "http://en.wikipedia.org/w/" + place,
success: function(result) {
callback(result);
}
});
}
for (var i = 0; i < places.length; i++) {
wikiInit(places[i], function(wikiString) {
self.items.push(wikiString);
console.log(self.items());
});
}
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: items">
<li data-bind="text: $data"></li>
</ul>
正如您所看到的,每次运行时,您都有机会,结果会出现故障。
选项1 是splice new items into the array所在位置(而非使用push
)。这是IMO有点复杂的方法,我将把代码留给读者。
选项2 ,一种可能更简单的方法是预先准备数组,并在回调中填充数组。例如。像这样:
// Mock Ajax stuff:
var $ = {
ajax: function(options) {
// Simulate unknown return moment with setTimeout:
setTimeout(function() {
options.success(options.url + " is a great city...");
}, Math.random() * 1500 + 50);
}
}
function Place(data) {
this.place = data.place;
this.wikistuff = ko.observable("");
}
function ViewModel() {
var self = this;
self.items = ko.observableArray([]);
var places = ["london", "brussels", "paris"];
function wikiInit(place, callback) {
var placeVm = new Place({ place: place });
self.items.push(placeVm);
$.ajax({
url: "http://en.wikipedia.org/w/" + place,
success: function(result) {
callback(result, placeVm);
}
});
}
for (var i = 0; i < places.length; i++) {
wikiInit(places[i], function(wikiString, placeVm) {
placeVm.wikistuff(wikiString);
});
}
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: items">
<li data-bind="text: wikistuff"></li>
</ul>
此结果始终按原始数组的顺序排列。
它目前总是显示子弹,甚至在回调完成之前。我这样做只是为了演示解决方案是如何工作的,但你可以很容易地做到这一点......
<li data-bind="text: wikistuff, visible: !!wikistuff()"></li>
......如果需要的话。