Reputation: 608
I'm having problems disabling a button while processing a "long" request on the server.
Our application runs on a Java Spring/Tomcat backend and the front is using AngularJS. Our users can click on a "Export" button to get a CSV file of some statistics. The problem is that this file is generated server-side by calling a URL like this:
<a ng-href="/exports?id={{the_id}}>Export</a>
and the response type is: application/octet-stream
.
The request works fine but can be a bit slow. I'd like to disable the button while the file is generating, and enable it after the "Save File" window has appeared. But I cannot intercept these events with a simple "synchrone" href.
I tried to process the request asynchronously with $http.get()
but this time, I do not know how to serve the file the same way to the user when the process is done (the way Mega does it for example, for people who have already used it).
Thanks in advance !
PS: I know that, making the processing faster is another solution...but it is not really possible for now, and not the point :)
EDIT: Problem solved thanks to Ed answer, with some modifications (I don't know if is a "good" way to do this, but actually it works for me exactly the way I want).
$scope.processExport = function(campaignId) {
if (!$scope.exportProcessing) {
$scope.exportProcessing = true;
$http.get('my_generating_url').success(function(response) {
$scope.exportProcessing = false;
$window.location.href = 'url_to_retrieve_the_file_with_' + response.fileName;
}).error(function() {
$scope.exportProcessing = false;
});
}
}
And the corresponding HTML:
<button ng-click="processExport(the_id)" ng-disabled="exportProcessing">Export</button>
And my_generating_url
is just returning the file name when it has been successfully generated.
Upvotes: 5
Views: 9086
Reputation: 19098
What you are trying to do is quite difficult.
One approach is to modify the the way the server works: instead of accepting the request, then replying with the file itself when it is generated, the flow could be the following:
GET /exports?:id
public/tmp/somefile
www.server.com/tmp/somefile
)Then, on the client you could do something like this:
function getExportedFile(id){
$scope.exporting = true;
$http.get('/exports?id=' + id)
.then( function (response) {
$scope.exporting = false;
$location.path(response.data);
})
.catch( function (error) {
// TODO: handle errors
});
}
Which would work with:
<button ng-click = "getExportedFile(fileId)"
ng-disabled = "exporting">
Download Exported File
</button>
Upvotes: 4
Reputation: 1500
You should be using a promise along with your $http
request and in the success function you should set a scope variable to true (meaning: loading finished). Initially, you should set this variable as false.
// in your controller
$scope.myData.loadComplete = '';
// below you call your service/factory to obtain your data and within the
// success function you will change the variable to true
{
// other code here
$scope.myData.loadComplete = 'disabled';
}
Then you can have your button disabled
during the time your myData.loadComplete
scope variable is false.
<button disabled="{{myData.loadComplete}}">Disabled</button>
For your reference, see the Docs:
Upvotes: 0
Reputation: 1582
There is a workaround that can use $http by adding an iFrame to the DOM, then setting the src to the file url on the server. This will trigger the browsers default action for the file type:
$http.post({url to create the file})
.success(function (data) {
if ($('#iframe').length == 0) {
var $iframe = $('<iframe id="iframe" style="display: none"></iframe>');
$('body').append($iframe);
}
$('#iframe').attr('src', {{url to retrieve the file}})
})
You will need to change the setting of the 'src' attribute to suit your situation.
Upvotes: 0