Knockout.js与多个getJSON请求绑定

时间:2016-03-26 17:47:13

标签: knockout.js getjson

我的示例正在运行,但我对ko.applyBindings()语句的位置感到困惑。我使用this approach从单个getJSON请求填充我的ViewModel。但是假设我需要2个getJSON请求。我移动了" var viewModel = new MyViewModel();"在getJSON之外,但ko.applyBinding()在两个getJSON方法中,我明白你不应该有2个绑定到同一个VM。我尝试在getJSON下面移动ko.applyBinding(),但没有任何效果。所以我将ko.applyBinding()放在其中一个getJSON方法中,并调用VM方法从另一个JSON调用中设置变量。它似乎有效,但我担心如果JSON请求在不同时间返回,则存在可能导致问题的时序问题。

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)不能移动到此脚本的底部?我试过了,但我的阵列都没有填充。

  

更新:是的,有时间问题。有时第二个"状态"数组在UI中更新,有时则不会。它显然取决于getJSON首先返回。所以我确实需要找到解决这个问题的方法。

以下是在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);
    });
});

2 个答案:

答案 0 :(得分:1)

问题在于您将新值设置为可观察数组,并且不将新对象分配给绑定属性。

而不是分配:

viewModel.types = jTypes;

我建议使用更新:

//viewModel.types(jTypes);
viewModel.types(["type a", 'type b', 'type c']);

我创建了一个示例(请求通过setTimeout模拟),启动数组为空,“times”在1秒内更新,“状态”在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 -->

答案 1 :(得分:0)

请注意,在这个答案中,我明确地重新发明了轮子,以显示这是如何工作的基本概念。有些库,包括你似乎已经使用过的库(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的承诺组合。

作为脚注,您还可以考虑直接运行applyBindings,并创建一个与空数组一样好看的视图。然后,当promises返回时,UI会自动更新。