AngularJS,如何使用服务捕获HTTP数据并将其绑定到我的控制器?

时间:2016-07-19 20:10:47

标签: javascript angularjs angularjs-scope angularjs-service angularjs-http

我有一个API调用很好,但是我想在几个控制器上使用它,所以我把它移到它自己的服务上。我遇到了看似经典的Scope问题或对Angular的摘要周期的误解。

'use strict';
myApp.factory('Stuff',['$http', function ($http) {
  var Stuff = {};
  Stuff.data = {};
  Stuff.api = 'http://localhost:8080/api/';
  Stuff.getStuff = function() {
    var http_stuff_config = {
      method: 'GET',
      url: Stuff.api + 'stuff/'
    };
    $http(http_stuff_config).then(function successCallback(response) {
      Stuff.data = (response.data);
      console.log(Stuff.data); // Returns populated object. 
    },function errorCallback(response) {
      console.log(response.statusText);
    });
  };
  Stuff.getStuff();
  console.log(Stuff.data); // Returns empty object.
  return Stuff;
}]);

myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
  $scope.stuff = Stuff;
  console.log($scope.stuff.data); // Returns empty object.
  $scope.stuff.getJobs();
  console.log($scope.stuff.data); // Returns empty object.
}]);

这是一个很大的线索。上面的基本输出依次是......

  1. 空对象(在调用方法后服务中)
  2. 空对象(在调用方法之前的控制器中)
  3. 空对象(在调用方法后的控制器中)
  4. 填充对象(在服务方法执行中)
  5. 填充对象(从控制器执行方法)
  6. 因此,在getStuff()方法的范围和Angular的操作顺序之间,我正在做一些非常愚蠢的事情。提前谢谢。

4 个答案:

答案 0 :(得分:1)

您需要在服务上添加退货,否则承诺将不会返回给控制器。将退货存储在服务中并且不将结果返回给控制器是不好的做法。

这被认为是不好的做法,因为每次更新服务数据时,每个人都需要将$scope.$watch应用于服务以查找更新。这在大型应用程序中可能非常昂贵。

最好的想法是将数据返回给调用控制器(如果你不需要缓存它,我们可以稍后讨论)并让控制器通过promise service.getthing().then(function(result){});

访问它。
myApp.factory('Stuff',['$http', function ($http) {
  var Stuff = {};
  Stuff.data = {};
  Stuff.api = 'http://localhost:8080/api/';
  Stuff.getStuff = function() {
    var http_stuff_config = {
      method: 'GET',
      url: Stuff.api + 'stuff/'
    };
    return $http(http_stuff_config).then(function successCallback(response) {
      return response.data;
      console.log(Stuff.data); // Returns populated object. 
    },function errorCallback(response) {
      console.log(response.statusText);
    });
  };
  Stuff.getStuff();
  console.log(Stuff.data); // Returns empty object.
  return Stuff;
}]);




myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
  $scope.stuff = Stuff;
  console.log($scope.stuff.data); // Returns empty object.
  $scope.stuff.getJobs().then(function(result) {$scope.stuff = result; console.log(result);});
  console.log($scope.stuff.data); // Returns empty object.
}]);

答案 1 :(得分:0)

请记住$scope.stuff.getJobs()是异步

(意味着您实际上无法在下一行调用console.log($scope.stuff.data)并获取数据)

现在,如果您有一个类似<span ng-bind="stuff.data.property">之类的视图,您可以看到它的工作正常,因为当异步函数完成时,视图会自动更新。 (这是角度的一部分)

答案 2 :(得分:0)

我建议你不要将结果存储在服务本身(Stuff.data)中。只需在getStuff函数中返回数据,然后让appController的作用域存储数据。

答案 3 :(得分:0)

你需要明白,当你运行$ http时,它正在发出一个AJAX请求。因此它不会立即返回结果。

因此,如果您尝试使用来自$ scope.stuff.getJobs()的数据;在调用此函数后,您可能立即得到任何结果。

你应该做的是让你的Stuff.getJobs()返回一个promise,并使用promise.then(你自己的成功处理程序)来正确处理返回的响应。

我已经清理了一点代码。以下是从Yahoo Weather API检索数据的代码的运行示例。

您可以在CODEPEN上播放。

HTML:

<div ng-app="myApp" ng-controller="appController">
  <p>{{data}}</p>
</div>

JS:

var myApp = angular.module("myApp", []);

myApp.factory('Stuff',['$http', function ($http) {
  var Stuff = {};
  Stuff.data = {};
  //sample yahoo weather api
  Stuff.api = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';

  Stuff.getData = function() {
    var http_stuff_config = {
      method: 'GET',
      url: Stuff.api + 'stuff/'
    };
    return $http(http_stuff_config);
  };

  return Stuff;
}]);

myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
  $scope.data = "$http service not ran";

  var uncompletedAjaxCall = Stuff.getData();
  uncompletedAjaxCall.then(
    function(responseData){
      $scope.data = responseData;
    }, 
    function(errorMsg){}
  );

}]);