等待ajax结果绑定淘汰赛模型

时间:2013-11-21 12:53:13

标签: javascript jquery ajax json knockout.js

我有调用ajax GET的getGeneral函数。当ajax收到数据(json)时,它会从给定的json创建KO模型并返回创建的KO。

创建Knockout模型并分配值时,应调用knockout applybindings。这是我的代码:

定义GeneralModel和一些相关功能(内部" GeneralModel.js"):

var GeneralModel = function() {

   //for now it is empty as data ar binded automatically from json
   // CountryName is one of the properties that is returned with json
} 

function getGeneral(pid) {
    $.ajax({
        url: "/api/general",
        contentType: "text/json",
        dataType: "json",
        type: "GET",
        data: { id: pid},
        success: function (item) {
            var p = new GeneralModel();
            p = ko.mapping.fromJS(item);
            return p;
        },
        error: function (data) {

        }
    });    
}

这是从另一个文件(GeneralTabl.html)调用的,它应该调用get函数,applyBindings来更新UI:

var PortfolioGeneral = getGeneral("@Model.Id");
ko.applyBindings(PortfolioGeneral, document.getElementById("pv-portfolio-general-tab"));

但是,在这种情况下,我收到错误(未定义CountryName)。这是因为applyBindings在ajax返回数据之前发生,所以我正在使用applyBindings来清空具有未定义属性的模型。

从Json到Model的映射在这里发生并且是assignes值:      p = ko.mapping.fromJS(item);

我也可以用所有字段填写GeneralModel,但是没有必要(我猜):

  var GeneralModel = function() {    
      CountryName = ko.observable();
      ...
  } 

它仍会出现错误" CountryName未定义"。

解决方案是什么?

1)我可以以某种方式在getGeneral内移动GeneralModel,因此获取数据将成为GeneralModel初始化的一部分吗?

2)也许我应该以某种方式做"等待ajax结果"然后才applyBindings

我相信还有其他选择,我对KO和纯JS不太熟悉。

注意:我完全理解这是因为Ajax是异步调用,所以问题是如何重构这段代码,考虑到我有两个单独的文件,我需要从外部调用getGeneral,它应该返回一些变量。

1 个答案:

答案 0 :(得分:5)

尝试使用返回的promise接口:

function getGeneral(pid) {
    return $.ajax({
        url: "/api/general",
        contentType: "text/json",
        dataType: "json",
        type: "GET",
        data: {
            id: pid
        }
    });
}

getGeneral("@Model.Id").done(function (item) {
    var p = new GeneralModel();
    p = ko.mapping.fromJS(item);
    ko.applyBindings(p, document.getElementById("pv-portfolio-general-tab"));
}).fail(function () {
    //handle error here
});