简体   繁体   中英

Where should I put my response handler code for AJAX calls in Angular.js?

I'm fairly new to Angular.js. I try to keep my code organized, in particular, my controllers thin. My current setup is as follows:

User events get picked up by my controller, eg a button click will invoke $scope.upgrade() in controller.

$scope.upgrade = function() {
  $scope.submitting = true // disable upgrade button
  payment.chargeCreditCard($scope);
};

Then the payment service takes over and does the actual work which involves making AJAX call to backend. In my payment service module, the code is something like:

payment.chargeCreditCard = function($scope) {
  $http({
    method: 'post',
    url: endpoint,
    data: data
  }).success(function() {
    // do things...
  }).error(function() {
    $scope.error = "Something wrong happened."; // $scope was passed in from controller
    $scope.submitting = false; // Re-enable the button
  });
};

My question is, it feels wrong to pass $scope from controller to service. Services should be independent and should not care about things like setting the value of $scope.error and $scope.submitting .

What is the Angular way of doing this?

== UPDATE ==

So one solution I came up with is make the AJAX call in the service but return the result to controller. Something like:

// in controller
$scope.upgrade = function() {
  // call service...
  var response = payment.chargeCreditCard($scope);

  response
    .success(function() {
      // ...
    })
    .error(function() {
      // set $scope.error etc...
    });
};

But then the controller is still pretty fat and the only thing that's in service is just the AJAX call itself which makes it seem not very worthwhile to separate the code.

Return the result of the $http call in the service and use the success handler in your controller.

Controller

$scope.upgrade = function() {
  $scope.submitting = true // disable upgrade button
  payment.chargeCreditCard().success(function() {
    // do stuff
  }).error(function() {
    // Do other stuff
  });
};

Service

payment.chargeCreditCard = function() {
  return $http({
    method: 'post',
    url: endpoint,
    data: data
  });
};

Another way of doing it if this is not what you are after is using events. So in your service have the $rootScope has dependencies and use the $broadcast method.

Controller

$scope.upgrade = function() {

  $scope.submitting = true // disable upgrade button
  payment.chargeCreditCard();

  $scope.$on("chargeCreditCard:success", function(ev, data) {
    // Do stuff
  });

  $scope.$on("chargeCreditCard:error", function(ev, err) {
    // Do other stuff
  });
};

Service

payment.chargeCreditCard = function() {
  return $http({
    method: 'post',
    url: endpoint,
    data: data
  }).success(function(data) {
    $rootScope.$broadcast("chargeCreditCard:success", data);
  }).error(function(err) {
    $rootScope.$broadcast("chargeCreditCard:error", err);
  });
};

But I guess the controller is as "fat", also not sure what is wrong with the controller containing the code that affect the property of its scope. By passing the scope you are making the service dependent on the controller or at least a set of properties on a scope/object which kind of go against the separation of concern.

The role of the service in this case would be to get the data and return it, one way or the other, but the service role should not be to modify controller properties.

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