Joao Joao - 1 year ago 382
AngularJS Question

Angularjs how to cancel resource promise when switching routes

I'm just getting my feet wet with Angularjs. I have an issue which I think has something to do with promises.

Let's say I load route 'A' which makes several ajax requests through it's controller:

allSites = AllSites.query({ id:categoryID });

//add stuff to the scope and does other things
//(including making another ajax request)

Then I have route 'B' which makes it's own API request through it's controller:

$scope.categories = Category.query();

Here's the factory service currently used by route 'A':

return $resource('api/categorySites/:id');

When I first view route 'A' but then switch to 'B' before 'A' is finished loading, route 'B' sits and waits for everything initially requested in 'A' to finish (actually, the query() request is made, but it won't resolve until the one from 'A' does, at that point, the stuff inside
continues to happen, even though I don't need it as I'm now on another route.

As you can see in my devtools timeline, the green line indicates when I switched to route 'B'. The request for route 'B' didn't resolve until the two requests above did (a request that is usually very fast). (at which point I'm able to use the view as a user). Then, after that, more promises resolve from route 'A'.

My devtools

I've searched everywhere for an answer and can only find people that want to "defer" the route loading until promises are resolved. But in my case I almost want the opposite. I want to kill those requests when I switch.

Here's someone else with the same, unanswered question: Reject Angularjs resource promises

Any help is appreciated.

Answer Source

First of all, I decided I needed to use $http since I couldn't find any solution that used $resource, nor could I get it to work on my own.

So here's what my factory turned into, based on @Sid's answer here, using the guide at


    function getSites(categoryID) {

        // The timeout property of the http request takes a deferred value
        // that will abort the underying AJAX request if / when the deferred
        // value is resolved.
        var deferredAbort  = $q.defer();

        // Initiate the AJAX request.
        var request = $http({
            method: 'get',
            url: 'api/categorySites/'+categoryID,
            timeout: deferredAbort.promise

        // Rather than returning the http-promise object, we want to pipe it
        // through another promise so that we can "unwrap" the response
        // without letting the http-transport mechansim leak out of the
        // service layer.
        var promise = request.then(
            function( response ) {
                return( );
            function() {
                return( $q.reject( 'Something went wrong' ) );

        // Now that we have the promise that we're going to return to the
        // calling context, let's augment it with the abort method. Since
        // the $http service uses a deferred value for the timeout, then
        // all we have to do here is resolve the value and AngularJS will
        // abort the underlying AJAX request.
        promise.abort = function() {

        // Since we're creating functions and passing them out of scope,
        // we're creating object references that may be hard to garbage
        // collect. As such, we can perform some clean-up once we know
        // that the requests has finished.
            function() {
                promise.abort = angular.noop;
                deferredAbort = request = promise = null;

        return( promise );

    // Return the public API.
        getSites: getSites


Then, in my controller (route 'A' from my problem):

var allSitesPromise = AllSites.getSites(categoryID);


    // do stuff here with the result

I wish the factory wasn't so messy, but I'll take what I can get. However, now there's a separate, related issue Here where, though the promise was cancelled, the next actions are still delayed. If you have an answer for that, you can post it there.