wait for ajax result to bind knockout model

2019-02-27 23:14发布

问题:

I have getGeneral function that calls ajax GET. When ajax recieves data (json), it creates KO model from given json and returns created KO.

When Knockout model is created and values are assigned, knockout applybindings should be called. Here is my code:

Defines GeneralModel and some related functions (inside "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) {

        }
    });    
}

This is called from another file (GeneralTabl.html), it should call get function and applyBindings to update UI:

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

However, in this scenario I am getting error (CountryName is not defined). This is because applyBindings happens before ajax returns data, so I am doing applyBindings to empty model with undefined properties.

Mapping from Json to Model happens here and is assignes values: p = ko.mapping.fromJS(item);

I can also fill in GeneralModel with all fields, but it is not necessary (I guess):

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

It will still give an error "CountryName is not defined".

What is the solution?

1) Can I somehow move getGeneral inside GeneralModel, so get data would be part of GeneralModel initialization?

or

2) Maybe I should somehow do "wait for ajax results" and only then applyBindings?

or

I believe there are other options, I am just not so familiar with KO and pure JS.

Note: I fully understand that this is because Ajax is Async call, so the question is how to restructure this code taking into account that I have two seperate files and I need to call getGeneral from outside and it should return some variable.

回答1:

Try using the returned promise interface:

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
});