0

I'm using angularjs in my project. I come across a problem. There are two buttons A and B on the page, they call same function which gets remote data from server. When i click A then click B, it sends two requests, but sometimes request B returned earlier then request A, so last i render data from request A on the page which I should render data from request B. Now I have a solution below:

app.controller("controller", function($scope) {
    $scope.lastTimeStamp = null;
    $scope.getData = functio() {
        $scope.lastTimeStamp = new Date().getTime();
        var temp = angular.copy(t);
        $http({}).success(function() {
            if($scope.lastTimeStamp == temp) {
                // this is the data from last request
            }
        })
    }
});

every time call $scope.getData(), I update $scope.lastTimeStamp and var temp with same value to ensure $scope.lastTimeStamp is the actual last one, and compare it with temp in the call back. This works. But this situation is common is my project, if solve it in this way, every time I need to do this which has non business logic with business logic. so I wonder if there is a common solution to solve this? any help?

Rob Wilson
  • 1,123
  • 1
  • 8
  • 13
aldrich
  • 81
  • 1
  • 4

2 Answers2

0

You never know when a request will return a response. So you have to use promises. Angular has the $q service for this porpoise. So you could create variable to hold the promise of A and when it returns then run the request from method B. But this have some side effects. What will happend if the user clicks B and never click A?

//controller

var deferA;

$scope.methodA = function () {
  deferA = $q.defer();
  $http('service-a-url').then(function (response) {
    // render your response 
    deferA.resolve(reponse);
  }, function (error) {
    // notify about the error
    deferA.reject(error);
  });
}


$scope.methodB = function () {
  if (deferA) {
    $q.when(deferA).then(function () {
      $http('service-b-request').then(function () {
        // render your data
      });
    });
  }
}

You could use $q.all too

Raulucco
  • 3,406
  • 1
  • 21
  • 27
  • See [Is this a “Deferred Antipattern”?](http://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern) – georgeawg Nov 27 '15 at 10:18
  • I see your point but you need to execute some render logic before resolving the defer. Or group both request inside a same button. But in the question you want to have two separate methods for each button. It would be better to group everything in one method and group the request with the `$q.all` – Raulucco Nov 27 '15 at 10:28
  • Thanks for reply, actually there is no methodA and methodB, button A and button B call same method and just pass in different args. but using promise seems could solve it, i could't try it now for some reason. I'll try it tomorrow. – aldrich Nov 29 '15 at 12:47
0

Save the promise from the previous click and chain from that.

var vm = $scope;  
vm.prevClickPromise = $q.when(0);

vm.doClick = function doClick(someRequest) {        
    vm.prevClickPromise = vm.prevClickPromise.then ( function () {
        //Make and return Http request
        return $http(someRequest);
    }) .then (function (response) {
        //render data
        vm.data = response.data;
    }) .catch (function (error) {
        //log error
    })
};

By chaining off the previous click's promise, the subsequent $http request will wait until the previous $http request has resolved with either with data or an error. If previous requests have already resolved, subsequent requests will start immediately.

Notice that data is returned differently with the .then method than with the .success method.

Deprecation notice

The .success and .error methods of the $http service have been deprecated. For more information on the deprecation (or should say failure) of the .success and .error methods see the AngularJS $http Service API Reference.

georgeawg
  • 48,608
  • 13
  • 72
  • 95