如何使控制器等待承诺从角度服务解决

时间:2014-09-17 20:24:01

标签: javascript ajax angularjs promise angularjs-service

我有一个向后端发出AJAX请求的服务

服务:

    function GetCompaniesService(options)
    {
        this.url = '/company';
        this.Companies = undefined;
        this.CompaniesPromise = $http.get(this.url);

    }

控制器:

var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(data){
   $scope.Companies = data;
});

我希望我的服务能够处理“.then”功能而不必在我的控制器中处理它,并且我希望能够让我的控制器在服务中的承诺之后对服务中的数据进行操作已经解决了。

基本上,我希望能够像这样访问数据:

var CompaniesOb = new GetCompanies();
$scope.Companies = CompaniesOb.Companies;

承诺的解决方案是在服务本身内部处理的。

这可能吗?或者我是否可以访问该承诺的唯一方法是从服务外部解决该问题?

3 个答案:

答案 0 :(得分:4)

如果你想要的只是处理服务本身$http的响应,你可以在服务中添加then函数,然后从那里return进行更多处理。 {1}}功能,如下所示:

then

但你仍然会在控制器中使用一个承诺,但是你得到的回报将在服务中得到处理。

function GetCompaniesService(options) {
  this.url = '/company';
  this.Companies = undefined;
  this.CompaniesPromise = $http.get(this.url).then(function(response) {
    /* handle response then */
    return response
  })
}

答案 1 :(得分:3)

实现这一点没有问题!

您必须记住的主要事项是您必须在服务中保留相同的对象引用(并且在javascript数组中是对象)。

这是我们简单的HTML:

<div ng-controller = "companiesCtrl"> 
  <ul ng-repeat="company in companies">
     <li>{{company}}</li>
  </ul>
</div>

以下是我们的服务实施:

serviceDataCaching.service('companiesSrv', ['$timeout', function($timeout){
  var self = this;

  var httpResult = [
    'company 1',
    'company 2',
    'company 3'
  ];

  this.companies = ['preloaded company'];
  this.getCompanies = function() {
    // we simulate an async operation
    return $timeout(function(){
      // keep the array object reference!!
      self.companies.splice(0, self.companies.length);

      // if you use the following code:
      // self.companies = [];
      // the controller will loose the reference to the array object as we are creating an new one
      // as a result it will no longer get the changes made here!
      for(var i=0; i< httpResult.length; i++){
        self.companies.push(httpResult[i]);
      }
      return self.companies;
    }, 3000);                    
}}]);   

最后控制器就像你想要的那样:

serviceDataCaching.controller('companiesCtrl', function ($scope, companiesSrv) {
  $scope.companies = companiesSrv.companies;
  companiesSrv.getCompanies();
});

<强>说明

如上所述,诀窍是保持服务和控制器之间的引用。一旦您尊重这一点,您就可以将控制器范围完全绑定在服务的公共属性上。

Here a fiddle that wraps it up.

在代码的注释中,您可以尝试取消注释不起作用的部分,您将看到控制器如何丢失引用。实际上,控制器将继续引用旧阵列,而服务将更改新阵列。

最重要的一件事:请记住$ timeout在rootSCope上触发$ apply()。这就是为什么我们的控制器范围是单独刷新的原因&#39;没有它,如果您尝试用普通的setTimeout()替换它,您将看到控制器没有更新公司列表。 要解决这个问题,你可以:

  • 如果您的数据是使用$ http获取的话,请不要做任何事情,因为它会在成功时调用$ apply
  • 将结果包裹在$ timeout(...,0);
  • 在服务中注入$ rootSCope,并在异步操作完成时调用$ apply()
  • 控制器中的
  • 在getCompanies()承诺成功
  • 上添加$ scope。$ apply()

希望这有帮助!

答案 2 :(得分:-1)

您可以将$ scope传递给GetCompanies,并将$ scope.Companies设置为服务中的数据

 function GetCompaniesService(options,scope)
 {
    this.url = '/company';
    this.Companies = undefined;
    this.CompaniesPromise = $http.get(this.url).then(function(res) {
      scope.Companies = res;
    });

 }

您必须注意使用数据的顺序。这是承诺开始的原因。