Skip to content

Instantly share code, notes, and snippets.

@pertrai1
Forked from bennadel/abort-angularjs.htm
Created April 25, 2014 10:08
Show Gist options
  • Save pertrai1/11284407 to your computer and use it in GitHub Desktop.
Save pertrai1/11284407 to your computer and use it in GitHub Desktop.
<!doctype html>
<html ng-app="Demo">
<head>
<meta charset="utf-8" />
<title>
Aborting AJAX Requests Using $http And AngularJS
</title>
<style type="text/css">
a[ ng-click ] {
color: red ;
cursor: pointer ;
text-decoration: underline ;
}
</style>
</head>
<body ng-controller="DemoController">
<h1>
Aborting AJAX Requests Using $http And AngularJS
</h1>
<p>
<a ng-click="loadData()">Load Data</a> -
<a ng-click="abortRequest()">Abort Request</a>
</p>
<!-- Show when data is loading. -->
<p ng-if="isLoading">
<em>Loading...</em>
</p>
<!-- Show when data has finished loading. -->
<ul ng-if="! isLoading">
<li ng-repeat="friend in friends">
{{ friend.name }}
</li>
</ul>
<!-- Initialize scripts. -->
<script type="text/javascript" src="../jquery/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="../angularjs/angular-1.2.4.min.js"></script>
<script type="text/javascript">
// Define the module for our AngularJS application.
var app = angular.module( "Demo", [] );
// -------------------------------------------------- //
// -------------------------------------------------- //
// I control the main demo.
app.controller(
"DemoController",
function( $scope, friendService ) {
// I determine if remote data is currently being loaded.
$scope.isLoading = false;
// I contain the data that we wan to render.
$scope.friends = [];
// I hold the handle on the current request for data. Since we want to
// be able to abort the request, mid-stream, we need to hold onto the
// request which will have the .abort() method on it.
var requestForFriends = null;
// ---
// PUBLIC METHODS.
// ---
// I abort the current request (if its running).
$scope.abortRequest = function() {
return( requestForFriends && requestForFriends.abort() );
};
// I load the remote data for the view.
$scope.loadData = function() {
// Flag the data is currently being loaded.
$scope.isLoading = true;
$scope.friends = [];
// Make a request for data. Note that we are saving a reference to
// this response rather than just piping it directly into a .then()
// call. This is because we need to be able to access the .abort()
// method on the request and we'll lose that original reference after
// we call the .then() method.
( requestForFriends = friendService.getFriends() ).then(
function( newFriends ) {
// Flag the data as loaded.
$scope.isLoading = false;
$scope.friends = newFriends;
},
function( errorMessage ) {
// Flag the data as loaded (or rather, done trying to load). loading).
$scope.isLoading = false;
console.warn( "Request for friends was rejected." );
console.info( "Error:", errorMessage );
}
);
};
}
);
// -------------------------------------------------- //
// -------------------------------------------------- //
// I am the friend repository.
app.service(
"friendService",
function( $http, $q ) {
// I get the list of friends from the remote server.
function getFriends() {
// 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/friends.cfm",
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( response.data );
},
function( response ) {
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() {
deferredAbort.resolve();
};
// 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.
promise.finally(
function() {
console.info( "Cleaning up object references." );
promise.abort = angular.noop;
deferredAbort = request = promise = null;
}
);
return( promise );
}
// Return the public API.
return({
getFriends: getFriends
});
}
);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment