【问题标题】:Knockout JS - update viewModel with AJAX CallKnockout JS - 使用 AJAX 调用更新 viewModel
【发布时间】:2014-09-23 06:52:24
【问题描述】:

有一些类似的问题,但没有帮助我解决我的问题。使用 AJAX 更新我的 viewModel 后,我无法在页面/视图上更新我的结果。如果我重新加载页面,我会收到有效的 AJAX 响应来更新视图,但当我单击 btnAdvancedSearch 时不会更新

我有简单的 HTML:

    <div>
        <input type="button" id="btnAdvancedSearch" data-bind="click: refresh" />
    </div>

    <div id="resultslist1" data-bind="template: { name: 'rest-template', foreach: restaurants }">
    </div>

我在文件加载时绑定:

$(document).ready(function () {
     ko.applyBindings(new RestaurantsListViewModel());
});

我的viewModel是这样的,在里面我调用了与按钮绑定的刷新

// Overall viewmodel for this screen, along with initial state
function RestaurantsListViewModel() {
    var self = this;
    self.restaurants = ko.observableArray([]);

    var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants = mappedRests;

    self.refresh = function () {
    updateRestaurantsList(); //Method executes AJAX and saves result to session.
    var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants= mappedRests2;
}

}

我在这里错过了什么?

谢谢

【问题讨论】:

  • 第一个应该是self.restaurants(mappedRests);。第二个是ajax,是异步的,需要在ajax的success回调中放入代码var mappedRests2 = $map(...); self.restaurants(mappedRests2);
  • 当我的 AJAX 完成后,结果会保存在 sessionStorage 中(一定是这样的)然后我从 sessionStorage 中填充 self.restaurants。这会是个问题吗?我的 console.log 显示已检索到值
  • 你写的方式,that two lines 立即执行(在 ajax 从服务器接收数据之前),ajax 将在未来完成,updateRestaurantsList() 不等待 ajax 完成。如果这听起来不熟悉,请阅读一些关于 ajax 的基本教程。
  • 我知道你在说什么,并且会尝试从这里直接调用 ajax 并绑定成功。但是为了测试,我将 console.log 放在最后一行之前,它会打印出没有在页面上呈现的良好、有效和更新的对象。
  • 你在ajax调用中使用async:false选项吗? (jQuery 文档不推荐)如果你这样做,self.restaurants(mappedRests2); 应该可以工作。

标签: ajax mvvm knockout.js viewmodel


【解决方案1】:
updateRestaurantsList(); //Method executes AJAX and saves result to session.

上面那行后面的注释表示这个方法是在进行异步调用。因此,很可能是在 sessionStorage 之前执行之后的行已经被填充。也许考虑让updateRestaurantsList 返回一个承诺。然后你可以更新你的代码是这样的:

updateRestaurantsList().then(function() {
    var mappedRests2 = $.map($.parseJSON(sessionStorage.getItem('searchResults')), function (item) { return new Restaurant(item) });
    self.restaurants= mappedRests2;
});

这样,在您的 updateRestaurantsList 方法完成之前,不会调用填充您的 mappedRests2 变量。

编辑 1

确保永远不要使用等号为 observable 赋值。

// Overall viewmodel for this screen, along with initial state
 function RestaurantsListViewModel() {
     var self = this;
     self.restaurants = ko.observableArray([]);

     var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')),     function (item) { return new Restaurant(item) });
      self.restaurants(mappedRests);

      self.refresh = function () {

    var latitude = sessionStorage.getItem('latitude');
    var longitude = sessionStorage.getItem('longitude');
    var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
    var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);

    searchResults.success(function (data) {
        var information = data.d;

        var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });

        self.restaurants(mappedRests2);
    });

  };
};

【讨论】:

  • 我在我的 AJAX 方法中这样做。在 self.restaurants= mappedRests2; 之前我 console.log 响应,这很好,但我的视图没有更新
【解决方案2】:

我尝试过像这样等待 AJAX 完成:

 // Overall viewmodel for this screen, along with initial state
 function RestaurantsListViewModel() {
     var self = this;
     self.restaurants = ko.observableArray([]);

     var mappedRests = $.map($.parseJSON(sessionStorage.getItem('searchResults')),     function (item) { return new Restaurant(item) });
      self.restaurants = mappedRests;

      self.refresh = function () {

    var latitude = sessionStorage.getItem('latitude');
    var longitude = sessionStorage.getItem('longitude');
    var query = '{"Accepts_Reservations":"' + $('#chkReservation').is(":checked") + '","Accepts_Cards":' + $('#chkAcceptsCards').is(":checked") + '"}';
    var searchResults = getRestaurantsAdvancedSearchAJAX(query, latitude, longitude, 40);

    searchResults.success(function (data) {
        var information = data.d;

        var mappedRests2 = $.map($.parseJSON(information), function (item) { return new Restaurant(item) });

        self.restaurants = mappedRests2;
    });

  };
};

编辑 1

一旦你像这样声明了你的 observable:

self.restaurants = ko.observableArray([]);

当您想更新 restaurants 时,您不能这样做:

self.restaurants = mappedRests2;

相反,您需要这样做:

self.restaurants(mappedRests2);

【讨论】:

  • 哈哈。我的意思是编辑我自己的答案,但我还是把它留在这里。
  • :) 试过 self.restaurants(mappedRests2);但得到 TypeError: self.restaurants 不是一个函数。您的回答很有道理,但这个错误是关于什么的?
  • knockout.js 要求所有要自动映射的字段的非空值。在这种情况下如何纠正?
  • 您的代码中似乎有几个区域使用等号为self.restaurants 赋值——一次使用mappedRests,一次使用mappedRests2。你确定你在这两个地方都更新了你的代码吗?
  • 哦,就是这样。显然,我遵循了一些 Knockout JS 实现的坏例子。您可以使用解决方案复制/粘贴我的代码,以便我给您投票
猜你喜欢
  • 2012-08-28
  • 2013-01-10
  • 2018-12-11
  • 2012-03-22
  • 2011-05-30
  • 2015-01-17
  • 2012-02-29
  • 1970-01-01
  • 2014-10-05
相关资源
最近更新 更多