最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to make controller wait for promise to resolve from angular service - Stack Overflow

programmeradmin5浏览0评论

I have a service that is making an AJAX request to the backend

Service:

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

    }

Controller:

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

I want my service to handle the ".then" function instead of having to handle it in my controller, and I want to be able to have my controller act on that data FROM the service, after the promise inside the service has been resolved.

Basically, I want to be able to access the data like so:

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

With the resolution of the promise being handled inside of the service itself.

Is this possible? Or is the only way that I can access that promise's resolution is from outside the service?

I have a service that is making an AJAX request to the backend

Service:

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

    }

Controller:

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

I want my service to handle the ".then" function instead of having to handle it in my controller, and I want to be able to have my controller act on that data FROM the service, after the promise inside the service has been resolved.

Basically, I want to be able to access the data like so:

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

With the resolution of the promise being handled inside of the service itself.

Is this possible? Or is the only way that I can access that promise's resolution is from outside the service?

Share Improve this question asked Sep 17, 2014 at 20:24 AxschechAxschech 2951 gold badge2 silver badges14 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

If all you want is to handle the response of $http in the service itself, you can add a then function to the service where you do more processing then return from that then function, like this:

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

But you'll still have use a promise in the controller, but what you get back will have already been handled in the service.

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

There is no problem to achieve that!

The main thing you have to keep in mind is that you have to keep the same object reference (and in javascript arrays are objects) in your service.

here is our simple HTML:

<div ng-controller = "paniesCtrl"> 
  <ul ng-repeat="pany in panies">
     <li>{{pany}}</li>
  </ul>
</div>

Here is our service implementation:

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

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

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

      // if you use the following code:
      // self.panies = [];
      // 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.panies.push(httpResult[i]);
      }
      return self.panies;
    }, 3000);                    
}}]);   

And finally the controller as you wanted it:

serviceDataCaching.controller('paniesCtrl', function ($scope, paniesSrv) {
  $scope.panies = paniesSrv.panies;
  paniesSrv.getCompanies();
});

Explanations

As said above, the trick is to keep the reference between the service and the controller. Once you respect this, you can totally bind your controller scope on a public property of your service.

Here a fiddle that wraps it up.

In the ments of the code you can try unment the piece that does not work and you will see how the controller is loosing the reference. In fact the controller will keep having a reference to the old array while the service will change the new one.

One last important thing: keep in mind that the $timeout is triggering a $apply() on the rootSCope. This is why our controller scope is refreshing 'alone'. Without it, and if you try to replace it with a normal setTimeout() you will see that the controller is not updating the pany list. To work around this you can:

  • don't do anything if your data is fetched with $http as it calls a $apply on success
  • wrap you result in a $timeout(..., 0);
  • inject $rootSCope in the service and call $apply() on it when the asynchronous operation is done
  • in the controller add a $scope.$apply() on the getCompanies() promise success

Hope this helps!

You can pass the $scope into GetCompanies and set $scope.Companies to the data in the service

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

 }

You have to be careful about the order in which you then use the data. That's kind of the reason behind a promise to begin with.

发布评论

评论列表(0)

  1. 暂无评论