angular.module("fileDownload", ['ngCookies']);
<!DOCTYPE html>
<html ng-app="fileDownload">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link data-require="bootstrap-css@3.1.1" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.js" data-semver="1.2.17"></script>
<script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.18/angular-cookies.js"></script>
<script src="app.js"></script>
<script src="controller.js"></script>
<script src="service.js"></script>
</head>
<body ng-controller="downloadCtrl">
<button ng-click="downloadFile()" ng-disabled="!!downloadFileText" ng-style="{ 'text-align': downloadFileText.indexOf('Loading') > -1 ? 'left' : 'center' }" style="width: 125px">
{{ downloadFileText || 'Export' }}
<i ng-show="downloadFileText === 'Loaded'" class="glyphicon glyphicon-ok-circle"></i>
<i ng-show="downloadFileText === 'Failed'" class="glyphicon glyphicon-ban-circle"></i>
</button>
</body>
</html>
body {
padding: 20px;
}
button {
background-color: #fff;
border-color: #ccc;
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
background-image: none;
border-radius: 4px;
}
.glyphicon-ban-circle {
color: red;
font-size: 12px;
}
.glyphicon-ok-circle {
color: green;
font-size: 12px;
}
angular.module("fileDownload").controller("downloadCtrl", function($scope, $timeout, $q, downloadService) {
$scope.downloadFile = function() {
var params = {};
var loadingText = 'Loading Data';
var options = ['.', '..', '...'];
$scope.downloadFileText = loadingText + options[0];
var promise = downloadService.validateBeforeDownload(params).then(null, function(reason) {
alert(reason);
// you can also throw the error
// throw reason;
return $q.reject(reason);
}).then(downloadService.downloadFile).then(function() {
$scope.downloadFileText = 'Loaded';
}, function() {
$scope.downloadFileText = 'Failed';
}, function(i) {
i = (i + 1) % 3;
$scope.downloadFileText = loadingText + options[i];
});
promise.
finally(function() {
$timeout(function() {
delete $scope.downloadFileText;
}, 2000);
});
};
});
angular.module("fileDownload").factory("downloadService", function($interval, $timeout, $q, $cookieStore) {
var generateIframeDownload = function() {
var iframe = document.createElement('iframe');
$cookieStore.put('download_file', 'true');
iframe.src = '/myserver/dowload';
iframe.style.display = "none";
document.body.appendChild(iframe);
}
var manageIframeProgress = function() {
var defer = $q.defer();
// notify that the download is in progress every half a second / do this for a maximum of 50 intervals
var promise = $interval(function() {
if (!$cookieStore.get('download_file')) {
$interval.cancel(promise);
}
}, 500, 50);
promise.then(defer.reject, defer.resolve, defer.notify);
promise.finally(function() {
$cookieStore.remove('download_file');
document.body.removeChild(iframe);
});
return defer.promise;
}
return {
validateBeforeDownload: function(config) {
var defer = $q.defer();
// notify that the download is in progress every half a second
$interval(function(i) {
defer.notify(i);
}, 500);
//mock response from server - this would typicaly be a $http request and response
$timeout(function() {
// in case of error:
//defer.reject("this file can not be dowloaded");
defer.resolve(config);
}, 3000);
return defer.promise;
},
downloadFile: function(config) {
generateIframeDownload();
var promise = manageIframeProgress();
//mock response from server - this would be automaticlly triggered by the file download compeletion
$timeout(function() {
$cookieStore.remove('download_file');
}, 3000);
return promise;
}
}
});