Knockout.js 与多个 getJSON 请求绑定
Knockout.js binding with multiple getJSON requests
我的示例工作正常,但我对 ko.applyBindings() 语句的位置感到困惑。我使用 this approach 从单个 getJSON 请求填充我的 ViewModel。但是假设我需要 2 个 getJSON 请求。我将 "var viewModel = new MyViewModel();" 移到 getJSON 之外,但是 ko.applyBinding() 在两个 getJSON 方法中,我知道你不应该对同一个方法有 2 个绑定虚拟机。我尝试将 ko.applyBinding() 移动到 getJSON 下方,但没有任何效果。所以我将 ko.applyBinding() 留在其中一个 getJSON 方法中,并调用 VM 方法来设置来自另一个 JSON 调用的变量。它似乎有效,但我担心如果 JSON 在不同时间请求 return 是否存在时间问题可能会导致问题。
var MyViewModel = function() {
var self = this;
self.types = ko.observableArray();
self.states = ko.observableArray();
self.loadStates = function (states){
self.states = states;
}
}
var viewModel = new MyViewModel();
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
viewModel.types = jTypes;
ko.applyBindings(viewModel);
});
$.getJSON('json/stateArray.json', function(jStates){
viewModel.loadStates(jStates);
//ko.applyBindings(viewModel);
});
});
我可以使用嵌套的 JSON 请求,但我希望它们同时执行。
为什么不能将 ko.applyBindings(viewModel) 移动到此脚本的底部?我试过了,但我的两个数组都没有填充。
Update: Yes, there is a timing problem. Sometimes the 2nd "states" array gets updated in the UI, and sometimes it does not. It evidently depends on which getJSON returns first. So I do need to find a solution to this problem.
这是在创建 viewModel 后移动 applyBindings 的尝试,但没有成功(见评论):
var MyViewModel = function() {
var self = this;
self.name = "myViewModel";
self.states = ko.observableArray();
self.types = ko.observableArray();
self.loadStates = function (states){
self.states = states;
console.log("Set states in viewModel: " + self.states);
}
}
var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
console.log("Setting types in viewModel: " + viewModel.name);
viewModel.types = jTypes;
//ko.applyBindings(viewModel);
});
$.getJSON('json/stateArray.json', function(jStates){
console.log("Setting states in viewModel: " + viewModel.name);
viewModel.loadStates(jStates);
//ko.applyBindings(viewModel);
});
});
请注意,在这个回答中,我明确地重新发明了轮子,以展示其工作原理的基本概念。有一些库,包括您似乎已经在使用的库 (jQuery),它们使这项任务变得更加容易和流畅。
基本上,您想要 运行 ko.applyBindings
,但只有在完成两个单独的异步请求之后。这是执行此操作的模式:
var viewModel = new MyViewModel();
function tryApplyBindings() {
if (viewModel.types().length > 0 &&
viewModel.states().length > 0) {
ko.applyBindings(viewModel);
}
}
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
console.log("Setting types in viewModel: " + viewModel.name);
viewModel.types = jTypes;
tryApplyBindings();
});
$.getJSON('json/stateArray.json', function(jStates){
console.log("Setting states in viewModel: " + viewModel.name);
viewModel.loadStates(jStates);
tryApplyBindings();
});
});
但是,请再次注意:这是重新发明轮子。您可以使用 jQuery 的 promise 功能(例如 this approach,也许)来制作更优雅和 DRY 的 promise 组合。
作为脚注,您也可以直接考虑 运行ning applyBindings
,并创建一个看起来也很适合空数组的视图。然后,当承诺 return 时,UI 会自动更新。
问题是您为可观察数组设置了新值,而不是将新对象分配给绑定属性。
而不是赋值:
viewModel.types = jTypes;
我建议使用更新:
//viewModel.types(jTypes);
viewModel.types(["type a", 'type b', 'type c']);
我创建了一个示例(通过 setTimeout 模拟请求),启动时数组为空,"times" 在 1 秒内更新,"states" 在 2 秒内更新:
var MyViewModel = function() {
var self = this;
self.name = "myViewModel";
self.states = ko.observableArray();
self.types = ko.observableArray();
}
var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
//$(function () {
// $.getJSON('json/typeArray.json', function(jTypes){
// viewModel.types(jTypes);
// });
// $.getJSON('json/stateArray.json', function(jStates){
// viewModel.states(jStates);
// });
//});
//$.getJSON('json/typeArray.json', function(jTypes){
setTimeout(function() {
viewModel.types(["type a", 'type b', 'type c'])
}, 1000);
//$.getJSON('json/stateArray.json', function(jStates){
setTimeout(function() {
viewModel.states(["state d", 'state e', 'state f'])
}, 2000);
// ever more - update types again in 5 sec
//$.getJSON('json/typeArray.json', function(jTypes){
setTimeout(function() {
viewModel.types(["type g", 'type h', 'type i', 'type j'])
}, 5000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>States:</div>
<!-- ko if: states().length === 0 -->
<div>There are no states for a while...</div>
<!-- /ko -->
<!-- ko foreach: states -->
<div data-bind="text: $data"></div>
<!-- /ko -->
<div>Types:</div>
<!-- ko if: types().length === 0 -->
<div>There are no types for a while...</div>
<!-- /ko -->
<!-- ko foreach: types -->
<div data-bind="text: $data"></div>
<!-- /ko -->
我的示例工作正常,但我对 ko.applyBindings() 语句的位置感到困惑。我使用 this approach 从单个 getJSON 请求填充我的 ViewModel。但是假设我需要 2 个 getJSON 请求。我将 "var viewModel = new MyViewModel();" 移到 getJSON 之外,但是 ko.applyBinding() 在两个 getJSON 方法中,我知道你不应该对同一个方法有 2 个绑定虚拟机。我尝试将 ko.applyBinding() 移动到 getJSON 下方,但没有任何效果。所以我将 ko.applyBinding() 留在其中一个 getJSON 方法中,并调用 VM 方法来设置来自另一个 JSON 调用的变量。它似乎有效,但我担心如果 JSON 在不同时间请求 return 是否存在时间问题可能会导致问题。
var MyViewModel = function() {
var self = this;
self.types = ko.observableArray();
self.states = ko.observableArray();
self.loadStates = function (states){
self.states = states;
}
}
var viewModel = new MyViewModel();
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
viewModel.types = jTypes;
ko.applyBindings(viewModel);
});
$.getJSON('json/stateArray.json', function(jStates){
viewModel.loadStates(jStates);
//ko.applyBindings(viewModel);
});
});
我可以使用嵌套的 JSON 请求,但我希望它们同时执行。
为什么不能将 ko.applyBindings(viewModel) 移动到此脚本的底部?我试过了,但我的两个数组都没有填充。
Update: Yes, there is a timing problem. Sometimes the 2nd "states" array gets updated in the UI, and sometimes it does not. It evidently depends on which getJSON returns first. So I do need to find a solution to this problem.
这是在创建 viewModel 后移动 applyBindings 的尝试,但没有成功(见评论):
var MyViewModel = function() {
var self = this;
self.name = "myViewModel";
self.states = ko.observableArray();
self.types = ko.observableArray();
self.loadStates = function (states){
self.states = states;
console.log("Set states in viewModel: " + self.states);
}
}
var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
console.log("Setting types in viewModel: " + viewModel.name);
viewModel.types = jTypes;
//ko.applyBindings(viewModel);
});
$.getJSON('json/stateArray.json', function(jStates){
console.log("Setting states in viewModel: " + viewModel.name);
viewModel.loadStates(jStates);
//ko.applyBindings(viewModel);
});
});
请注意,在这个回答中,我明确地重新发明了轮子,以展示其工作原理的基本概念。有一些库,包括您似乎已经在使用的库 (jQuery),它们使这项任务变得更加容易和流畅。
基本上,您想要 运行 ko.applyBindings
,但只有在完成两个单独的异步请求之后。这是执行此操作的模式:
var viewModel = new MyViewModel();
function tryApplyBindings() {
if (viewModel.types().length > 0 &&
viewModel.states().length > 0) {
ko.applyBindings(viewModel);
}
}
$(function () {
$.getJSON('json/typeArray.json', function(jTypes){
console.log("Setting types in viewModel: " + viewModel.name);
viewModel.types = jTypes;
tryApplyBindings();
});
$.getJSON('json/stateArray.json', function(jStates){
console.log("Setting states in viewModel: " + viewModel.name);
viewModel.loadStates(jStates);
tryApplyBindings();
});
});
但是,请再次注意:这是重新发明轮子。您可以使用 jQuery 的 promise 功能(例如 this approach,也许)来制作更优雅和 DRY 的 promise 组合。
作为脚注,您也可以直接考虑 运行ning applyBindings
,并创建一个看起来也很适合空数组的视图。然后,当承诺 return 时,UI 会自动更新。
问题是您为可观察数组设置了新值,而不是将新对象分配给绑定属性。
而不是赋值:
viewModel.types = jTypes;
我建议使用更新:
//viewModel.types(jTypes);
viewModel.types(["type a", 'type b', 'type c']);
我创建了一个示例(通过 setTimeout 模拟请求),启动时数组为空,"times" 在 1 秒内更新,"states" 在 2 秒内更新:
var MyViewModel = function() {
var self = this;
self.name = "myViewModel";
self.states = ko.observableArray();
self.types = ko.observableArray();
}
var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
//$(function () {
// $.getJSON('json/typeArray.json', function(jTypes){
// viewModel.types(jTypes);
// });
// $.getJSON('json/stateArray.json', function(jStates){
// viewModel.states(jStates);
// });
//});
//$.getJSON('json/typeArray.json', function(jTypes){
setTimeout(function() {
viewModel.types(["type a", 'type b', 'type c'])
}, 1000);
//$.getJSON('json/stateArray.json', function(jStates){
setTimeout(function() {
viewModel.states(["state d", 'state e', 'state f'])
}, 2000);
// ever more - update types again in 5 sec
//$.getJSON('json/typeArray.json', function(jTypes){
setTimeout(function() {
viewModel.types(["type g", 'type h', 'type i', 'type j'])
}, 5000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>States:</div>
<!-- ko if: states().length === 0 -->
<div>There are no states for a while...</div>
<!-- /ko -->
<!-- ko foreach: states -->
<div data-bind="text: $data"></div>
<!-- /ko -->
<div>Types:</div>
<!-- ko if: types().length === 0 -->
<div>There are no types for a while...</div>
<!-- /ko -->
<!-- ko foreach: types -->
<div data-bind="text: $data"></div>
<!-- /ko -->