3

I need to prevent sending the same request repeatedly to API before the previous request will give the response. I have found out some solutions. But, I don't want to disable the button while waiting for response because I have more API calls in my app.

I really need to do something in my $provider .config() .I found a way here(http://blog.codebrag.com/post/57412530001/preventing-duplicated-requests-in-angularjs).

But I need more clarification code. Any kind of reference about this is welcome.

Abhishek
  • 143
  • 5
user3391137
  • 431
  • 8
  • 26
  • 1
    Asking for ready to use code or for a tutorial is off-topic. If you have some code that you don't understand, then post the code, and tell what you don't understand. – JB Nizet Dec 17 '15 at 07:38
  • *"But i need more clarification code implementation.."* - please quote the parts that you need clarification for. As it is this question is asking for offsite resources or ready to use code which is off-topic here. BTW, I find the question mark after "thanks" funny. – T J Dec 17 '15 at 07:45
  • Needs tutorial with implementation – user3391137 Dec 17 '15 at 07:56
  • this blog is too old. don't use it. maybe this will help: http://stackoverflow.com/questions/18130808/preventing-dealing-with-double-button-clicks-in-angular – Avi Dec 17 '15 at 08:02
  • Look up interceptors. You do not need a custom service that checks if there are duplicate requests. You have an interceptor that keeps track of pending requests. If one is already running when a new one is made reject the new one, catch its reject and return a promise to use later. When the original request responds from the server intecept it, use its response to resolve your waiting requests mimicking a successful response. This way your calls to `$http` don't need to change. You could extend the `$http` config to opt out of this behavior. – ste2425 Dec 17 '15 at 08:33

4 Answers4

2

Lets say you have $http in your controller.js file.

Many request to server

$http.get('/link/to/file.php');

Just one request to server, no matter how many times you will call this method:

$http.get('/link/to/file.php', {cache: true});

Example:

(function() {
    'use strict';

    angular
            .module('yourModuleName')
            .controller('DashboardCtrl', DashboardCtrl);

    DashboardCtrl.$inject = ['$scope'];

    function DashboardCtrl($scope) {

       $scope.get = function () {
           $http.get('/link/to/file.php', {cache: true}).then(function(response) {
               // it will do GET request just once
               // later you will get the same response from cacheFactory
           })
       }
    }

}());
ssuperczynski
  • 3,190
  • 3
  • 44
  • 61
  • 1
    You missed the part where the OP writes "before the previous request will give the response". Your solution only works after the first response has returned. – AsGoodAsItGets Feb 14 '18 at 16:54
1

I would like to complement @VikasChauhan answer, however I do not have enough reputation to comment on his answer.

His code works great for me, except the part where he returns null. That causes Angular to throw a bunch of errors all over.

Instead of null, I simply reject the request:

return $q.reject(request);

Here's my function:

$httpProvider.interceptors.push(['$injector', '$q', function interceptors($injector, $q) {
    return {
        // preventing duplicate requests
        request: function request(config) {
            var $http = $injector.get('$http');
            var _config = angular.copy(config);
            delete _config.headers;

            function isConfigEqual(pendingRequestConfig) {
                var _pendingRequestConfig = angular.copy(pendingRequestConfig);
                delete _pendingRequestConfig.headers;

                return angular.equals(_config, _pendingRequestConfig);
            }

            if ($http.pendingRequests.some(isConfigEqual)) {
                return $q.reject(request);
            }

            return config;
        }
    };
}
]);

Hope this helps other people.

andreico
  • 121
  • 1
  • 7
  • 2
    I'm surprised if the part that you changed works, because `request` is not a valid variable/object in the block of code where you're calling `$q.reject(request)`. – AsGoodAsItGets Feb 14 '18 at 16:56
0

You can create a function to cancel the first http request, when calling the another one on the button click. Here is a reference that uses $q.defer() function that helped me on a similar issue: http://odetocode.com/blogs/scott/archive/2014/04/24/canceling-http-requests-in-angularjs.aspx

  • The request will still be made to the server however. Unless you call `$http` with a already rejected timeout. – ste2425 Dec 17 '15 at 09:24
  • You are right @ste2425, I put inside my http request `timeout: canceler.promise,`, and when I want the request to end, I just run `canceler.resolve();`. I'm not sure if it's the best solution, but it worked for me. – Armin Durakovic Dec 17 '15 at 12:33
0

In my project, i was facing this problem. I found a very useful working solution here

And implemented it inside the config:

function config($routeProvider, $httpProvider) {

    $httpProvider.interceptors.push(['$injector', function interceptors($injector) {
        // Manually injecting dependencies to avoid circular dependency problem
        return {
            // preventing duplicate requests
            'request': function request(config) {
                var $http = $injector.get('$http'),
                copiedConfig = angular.copy(config);

                delete copiedConfig.headers;
                function configsAreEqual(pendingRequestConfig) {
                    var copiedPendingRequestConfig = angular.copy(pendingRequestConfig);

                    delete copiedPendingRequestConfig.headers;

                    return angular.equals(copiedConfig, copiedPendingRequestConfig);
                }

                if ($http.pendingRequests.some(configsAreEqual)) {
                    debugger;
                    return null;
                }

                return config;
            }
        }
    }
    ]);
}
VikasChauhan
  • 61
  • 1
  • 3
  • 1
    I tried this and my concurrent requests get a result of null. How can I return the response from the other duplicate requests? Meaning, if I have two calls to an endpoint and one get's cancelled, can we return the results of the previous request? Thx. – matsientst Aug 02 '17 at 00:52