Reputation: 1645
In my Angular application the user can return to a previous screen (which is just hiding the current screen). The user may do this in the middle of a long running AJAX request. I'd like to cancel the Ajax request behind the scenes if this happens.
I can get ngresource's $cancelRequest to work, but it causes the error callback to be thrown. Is there a way to make that not happen or to distinguish a $cancelRequest from say a failed communication with the server? Thanks in advance.
Plunk (has some additional UI to it): http://plnkr.co/edit/tYj4FRQ9EaCTH4iW9PcL?p=preview
var app = angular.module("app", ["ngResource"]);
app.service("Photos", function($resource) {
return $resource(null, {}, {
getPhotos: {
url: "http://jsonplaceholder.typicode.com/photos",
method: "GET",
isArray: true,
cancellable: true
}
});
});
MyController.$inject = ["$log", "$timeout", "Photos"];
function MyController($log, $timeout, Photos) {
var vm = this;
vm.message = "Test message";
vm.result = null;
vm.photosRequest = null;
vm.$onInit = function() {
vm.message = "Test message";
vm.photosRequest = Photos.getPhotos({},
function(response) {
vm.callbackHit = "Good Callback Hit";
vm.result = response;
},
function(response) {
vm.callbackHit = "Bad Callback Hit (Don't want to see this if $cancelRequest was called, but do if there was an error talking to the server.)"
vm.result = response;
}
);
};
// Simulating a cancel request. How can I tell the error was a cancel and handle differently in the error callback?
$timeout(function() {
$log.info("cancelling request");
vm.photosRequest.$cancelRequest();
}, 25);
}
app.component("myComponent", {
templateUrl: "myComponent.html",
require: {},
bindings: {},
controller: MyController,
controllerAs: "vm"
});
Upvotes: 0
Views: 199
Reputation: 823
You could do something like this: http://plnkr.co/edit/NR9oyXQ8FMdouVAC1Hqx?p=preview
Created an additional property to keep track of your request:
var vm = this;
vm.message = "Test message";
vm.result = null;
vm.photosRequest = null;
// keep track of request state to avoid race conditions
vm.currentRequest = {id: 0, cancelled: false};
When you cancel the request, you update the state.
$timeout(function() {
$log.info("cancelling request");
vm.photosRequest.$cancelRequest();
vm.currentRequest.cancelled = true;
}, 25);
And in your callbacks, you check the state when deciding what to do:
vm.photosRequest = Photos.getPhotos({},
response => {
if (vm.currentRequest.id == requestNumber) { // ignore old requests resolving late
vm.callbackHit = "Good Callback Hit";
vm.result = response;
}
}, error => {
if (vm.currentRequest.id == requestNumber) { // ignore old requests resolving late
if (vm.currentRequest.cancelled) { // fail silently
$log.info('doing nothing in response to cancelled request');
} else {
vm.callbackHit = "Bad Callback Hit (Don't want to see this if $cancelRequest was called, but do if there was an error talking to the server.)"
vm.result = error;
}
}
});
Every time that you make a new request, you reset the state.
var requestNumber = ++vm.currentRequest.id;
vm.currentRequest.cancelled = false; // reset cancelled state on new request
vm.photosRequest = Photos.getPhotos({},...)
It's not the most elegant solution, but the request state doesn't seem to keep track if $cancelRequest is called or not, so you have to keep track yourself.
Upvotes: 1