简体   繁体   中英

Best practice to set up a service or factory for $http contacting to REST API in AngularJS

I've created $http and REST API interface in AnguarJS service as a function that gets injected into different controllers like this:

// Global service to share between states
.service("appSharedService", ['$http', function($http) {
  // Method: Returns list of all cities.
  this.restCitiesGet = function() {
     return $http.get('http://example/nkhorasaniec7/api/v0/city');
  };

  // Method:
  this.citiesGet = function() {
    this.restCitiesGet().success(function (data) {
        console.log(data);
        return data;
      })
  };
}])

console.log(data); returns the right json output when I call citiesGet() .

// Main controller that prints list of cities.
.controller('CityList', ['$scope', function($scope, appSharedService) {
  $scope.cities = appSharedService.citiesGet();
  console.log($scope.cities);
}]);

This is my controller injecting my service. console.log($scope.cities); here returns undefined.

$scope.cities value doesn't get changed after route calls this controller.

Is there something wrong with my setup?

Something interesting is that after I change route and come back to this controller again, this time $scope.cities have my REST data and everything's fine.

I think there's something wrong with timing or asynchronous functionality problem here that I'm not aware of.

EDIT:

I could have had $http in my controller and this works all well:

.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
  $http.get('http://localhost/nkhorasaniec7/api/v0/city').success(function (data) {
        $scope.cities = data;
      });
}]);

But I want to implement helper functions for this.

I would say that the common approach would be to return the promise directly to the controller, much like you have mentioned above by directly using the http request.

// Global service to share between states
.service("appSharedService", ['$http', function($http) {


// Method: Returning the promise
this.citiesGet = function() {
  return $http.get('http://example/nkhorasaniec7/api/v0/city');

 };
}])

Controller:

  .controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
appSharedService.citiesGet().success(function (data) {
      $scope.cities = data;
    });
 }]);

I think you are right about the timing issue. From what I understand, you are getting a promise, that at the moment you do console.log($scope.cities) is not yet resolved.

If you use $scope.cities inside your page, you should see the results as soon as they are loaded. Another option would be to use the promise then function if you really want to log.

$scope.cities = appSharedService.citiesGet().then(function(data) {
  console.log(data);
  return data;
};

Answering my own question:

I'm trying to make this happen in my a controller defined in my view using ng-controller , not a controller linked to a router (otherwise you could use resolve property like this Delaying AngularJS route change until model loaded to prevent flicker ).

And I want to use REST using $http as a factory/service helper function for a cleaner code.

// Global service to share between states
.service("appSharedService", ['$http', '$q', function($http, $q) {
  this.citiesGet = function() {
      var deferred = $q.defer();
      $http({method: 'GET', url: 'http://localhost/nkhorasaniec7/api/v0/city'}).success(function(data) {
        deferred.resolve(data);
      }).error(function(data, status) {
        deferred.reject(data);
      });
      return deferred.promise;
  };
}])

I used angular $q promise here.

// Our main controller that prints list of cities.
.controller('CityList', ['$scope', 'appSharedService', function($scope, appSharedService) {
  var promise = appSharedService.citiesGet();
  promise.then(
        function(data){$scope.cities = data;}
        ,function(reason){alert('Failed: ' + reason);}
  );
}])

And used then function to use that promise. And now it always updates $scope.cities in any situation that template loads (not just in ng-view)

You can use $q service

.service("appSharedService", ['$http', '$q', function($http, $q) {
  // Method: Returns list of all cities.
  this.restCitiesGet = function() {

    var deffered = $q.defer();
     $http.get('http://example/nkhorasaniec7/api/v0/city').then(
      //success
      function(response){
         deffered.resolve(response.data);},
      //error
         deffered.reject();

      );
    return deffered 
  };

and after that you can use promise in you controller

    .controller('CityList', ['$scope', function($scope, appSharedService) {
        $scope.cities = []
       appSharedService.citiesGet().then(
        //success
        function(result){
        angular.copy(result, $scope.cities)
        console.log($scope.cities);
       }, 
      //error
      function(){
      console.log("load error");

});

    }]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM