0

So I have a form that allows users to upload a file, the request sends the file, and the response is the file (to download).

However, as the processing of the file can take a few seconds, I want to show a "loading animation" while the file is being processed, but basically on the client side, while the browser awaits a response from the server (with the file to download).

I thought about something like this:

HTML:

<form role="form" action="/process" method="POST" enctype="multipart/form-data" name="fileform" id="fileform">
    <div class="col-lg-6">
        <label class="btn btn-default">Browse&hellip; <input type="file" style="display: none;" accept=".txt,text/plain" name="file" id="file">
        </label>
    </div>
    <div class="col-lg-6">
        <button type="submit" class="btn btn-default">Process</button>
    </div>
</form>
<div class="animationload" id="loader">
    <div class="osahanloading"></div>
</div>

JS

$("#fileform").submit(function(e) {
    e.preventDefault();
    $('#loader').show();
    var formData = new FormData();
    formData.append('file', $('input[type=file]')[0].files[0]);
    var action = $('#fileform').attr('action');
    jQuery.ajax({
        type: 'POST',
        url: action,
        data: formData,
        processData: false, 
        contentType: false, 
        success: $('#loader').hide()
    });
}); 

but this does not show the loader div, nor prompts the user to download the file...

Any other way I can achieve this?

Fede E.
  • 2,118
  • 4
  • 23
  • 39

1 Answers1

0

The success key should be a callback, not a jQuery object. According to the docs for $.ajax():

success

Type: Function(Anything data, String textStatus, jqXHR jqXHR) A function to be called if the request succeeds.

If you fix your code as such, it should work:

jQuery.ajax({
    type: 'POST',
    url: action,
    data: formData,
    processData: false, 
    contentType: false, 
    success: function(data) {
        $('#loader').hide();
        console.log(data);
    }
});

Even better: make use of the promise object returned by $.ajax() and chain .done() and your callback inside of it:

jQuery.ajax({
    type: 'POST',
    url: action,
    data: formData,
    processData: false, 
    contentType: false
}).done(function(data) {
    $('#loader').hide();
    console.log(data);
});
Terry
  • 63,248
  • 15
  • 96
  • 118
  • It fires the loader div and then hides it... but it doesn't prompt the user to open or save the file. – Fede E. May 09 '18 at 21:32
  • @FedeE. OP's code contains no additional code for file saving, so that's something I can't add on a whim. – Terry May 09 '18 at 21:33
  • The animation works now, but I do need to prompt the user to save or download the response. – Fede E. May 09 '18 at 21:35
  • @FedeE. There is no code that deals with file downloading... have you implemented any sort of that logic yet? I don't see that in your code. – Terry May 09 '18 at 21:38
  • Hmmm I don't think that's needed... the response from the upload request is the file. If I take jquery off the picture, once you submit the form, you get a download prompt from the browser. – Fede E. May 09 '18 at 21:40
  • It is up to your server to decide what kind of data it should send back once it responds to the AJAX request. Should it response with a blob? Some kind of plain text? In one way or another, the server response body can be accessed by the first argument in the success/done callback. It is up to you to decide how you want the browser to handle that response body. Alternatively you can make your endpoint return a URL that points to the file, and you can set `window.location` to that URL to force a download. Also, notice that your question is going out of scope of the title you gave it. – Terry May 09 '18 at 21:44
  • Well, server is already responding with the headers and the file stream so the browser is already able to interpret the “file download”. This is when you add jquery to display the animation. Anyways, you are right, i should rephrase the question to focus on how jquery could send that response to the browser. The option you suggested (responding with an url to download) can’t be used in this case as we are handling really sensitive data which can’t be stored in the server hard drives for later download, instead the file data is always treated as a stream in the server as well. Thanks tho! – Fede E. May 09 '18 at 22:02
  • It’s not as simple as forcing an octet stream from the server, because AJAX is a thin wrapper and can’t handle file streams. There are many solutions available tho: https://stackoverflow.com/questions/16086162/handle-file-download-from-ajax-post – Terry May 09 '18 at 22:07