【问题标题】:Knockoutjs: how to set the asynchronous API query result as the observablesKnockoutjs:如何将异步 API 查询结果设置为 observables
【发布时间】:2016-10-26 08:19:52
【问题描述】:

在我的应用程序中,我使用 knockoutJS 作为框架并希望查询 API 以获取数据。预期行为是在 KO 的 observables 中设置数据,然后 UI 将自动更新。 HTML如下:

    <div class="container">
      <div class="options-box">
        <h1>Restaurant Finder</h1>
        <ul class="category-list" data-bind="foreach: categoryList">
          <li class="category-item" data-bind="text:$data, click: $parent.queryRestaurant"></li>
       </ul>
       <ul class="location-list" data-bind="foreach: locationList">
         <li class="location-item" data-bind="text: title"></li> 
       </ul>
     </div>
   </div> 

JS代码如下:

  $(function(){
    console.log("debug inside the initmap")
    //The predefined restaurant categrory
    var restaurantCate = ["Sushi","Chinese Food","Coffee"];
    // the Location function for creating new location Knockout object 
    var Location = function(loc){
        return ko.observable(loc);
    };
    //the locatoinViewModel is the view model part for this application
    var locationViewModel =function() {
        var self = this;
        self.locationList = ko.observableArray([]);

        self.categoryList = ko.observableArray(restaurantCate);
        self.queryRestaurant = function(){
            console.log("hi");
            var foursquare_url = "https://api.foursquare.com/v2/venues/search";
            var Client_ID="xxx";
            var Client_Secret="xxx";
            foursquare_url += "?client_id=" + Client_ID + "&client_secret=" + Client_Secret + "&v=20130815" + "&ll=40.7413549,-73.9980244" + "&query=" + this;
            console.log(foursquare_url);
            queryFoursquare(foursquare_url);
        };
    };
    ko.applyBindings(new locationViewModel());
    //the queryFoursquare function 
    function queryFoursquare(queryurl){
        $.getJSON(queryurl,function(response){
            console.log(response["meta"]["code"]);
            var result = [];
            response["response"]["venues"].forEach(function(eachvenue){
                result.push({
                    title: eachvenue["name"],
                    location: {lat: eachvenue["location"]["lat"], lng:eachvenue["location"]["lng"]}
                });
            });
            locationViewModel.locationList(result);
        }).done(function(){
            console.log("done")
        }).fail(function(){
            alert("error happens during query data from Foursquare")
        });

    };    
  });

现在状态是:KO的viewmodel可以正常工作,API函数也可以获取数据。
问题是如何将result数组设置为KO的observableArraylocationList。如何处理这种异步查询的情况?

编辑: 我忘记添加错误消息:locationViewModel.locationList is not a function。

编辑 II

        var locationViewModel =function() {
        var self = this;
        self.locationList = ko.observableArray([]);

        self.categoryList = ko.observableArray(restaurantCate);
        self.queryRestaurant = function(){
            console.log("hi");
            var foursquare_url = "https://api.foursquare.com/v2/venues/search";
            var Client_ID="T3A2F5ZKOVEDWXZXLHFFNPU3DYTYIUZGPJELBWLJZVQFTALA";
            var Client_Secret="IM2R2QRHZR0CIOGCLYKGTOSBEPERM1JVA0X022CY3B4ZX41P";
            foursquare_url += "?client_id=" + Client_ID + "&client_secret=" + Client_Secret + "&v=20130815" + "&ll=40.7413549,-73.9980244" + "&query=" + this;
            console.log(foursquare_url);
            //queryFoursquare(foursquare_url);
            //Directly call the getJSON function inside viewmodel
            $.getJSON(foursquare_url,function(response){
                //console.log(response["meta"]["code"]);
                var result = [];
                response["response"]["venues"].forEach(function(eachvenue){
                    result.push({
                        title: eachvenue["name"],
                        location: {lat: eachvenue["location"]["lat"], lng:eachvenue["location"]["lng"]}
                    });
                });
                self.locationList(result)
            });
        };
    };

所以在将 AJAX 调用放回 viemmodel 之后。然后通过self.locationList,行为按预期进行。 如果我想将 API 调用分离成一个函数,如何访问 KO 的 observables?

谢谢

【问题讨论】:

  • 您正在向全世界公开您的客户 ID 和秘密...

标签: asynchronous knockout.js


【解决方案1】:

因此,根据更新后的帖子,归结为将 queryFoursquare 函数与 viewModel 分开。您可以从函数中返回result并将返回值分配给locationList,而不是尝试在函数内部访问locationList,如下所示 -

//return the result array - 

return $.getJSON(foursquare_url, function(response) {
  //console.log(response["meta"]["code"]);
  var result = [];
  response["response"]["venues"].forEach(function(eachvenue) {
    result.push({
      title: eachvenue["name"],
      location: {
        lat: eachvenue["location"]["lat"],
        lng: eachvenue["location"]["lng"]
      }
    });
  });
  return result;
});

// Assign the return value to the locationList observable Array.
queryRestaurant().done(function(result) {
    //Do stuff with the response.
    self.locationList(dataPreparedFromResult);
    console.log(self.locationList());
});

这将使您的代码更具可重用性。

编辑

因此,您需要从您的queryRestaurant 函数和.donehandler 中返回一个promise,您需要将数据推送到可观察数组中。因为,赋值是在 promise 返回之前完成的,所以你得到了undefined 作为输出。

希望这最终会有所帮助...

【讨论】:

  • 谢谢。但我认为关键是如何根据错误消息“locationViewModel.locationList is not a function”访问视图模型之外的locationList。请参阅我在原帖中的编辑。
  • 这个错误让我们现在处于不同的境地。我认为现在这取决于很多事情,queryFoursquare 函数保存在哪里,如果在一个单独的视图模型中,那么问题是在不同的视图模型/模块之间进行通信。你用什么来解决依赖关系等等。
  • THx。为了简化问题,我只有一个视图模型。这里发布的代码都是东西。问候
  • 嗨,你试试你的解决方案吗?事实上,我尝试了这种返回结果的方法。但这对我不起作用。似乎仍然是异步问题,locationList 设置为空...
猜你喜欢
  • 2019-12-29
  • 2020-06-01
  • 2019-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 2011-08-14
相关资源
最近更新 更多