1

I have a simple form for uploading a file that works well enough synchronously:

<form id="uploadForm" action="/upload" method="post" encType="multipart/form-data">
  <input type="file" id="file" name="file" accept=".csv" />
  <input type="text" name="comment" />
  <button type="submit">Upload</button>
</form>

How can I make this form upload the file asynchronously (without reloading the page?), and be notified when the upload is complete, and if there were any errors?

I know that the primary way to make an asynchronous request is to use an XMLHttpRequest, and I see that something like the following is now possible (I have not tested this code):

function handleLoad() {
  console.log(this.responseText);
}
function handleError(error) {
  console.error(error.stack);
}
function handleSubmit(e) {
  e.preventDefault();
  var form = document.getElementById('uploadForm');
  var request = new XMLHttpRequest();
  request.addEventListener('load', handleLoad);
  request.addEventListener('error', handleError);
  request.open("POST", "/upload");
  request.send(new FormData(form));
}

However, according to MDN, sending FormData, Blobs, Files, or ArrayBuffers is only supported in IE10+, and I want a backwards-compatible solution (which doesn't use jQuery).

There are plenty of answers to How can I upload files asynchronously?, but all of the answers I have read so far use jQuery or use the modern XMLHttpRequest method I described above.

I am using React and have no use for anything else jQuery offers, so I would like to keep my page download size smaller by solving this with vanilla JS.

Andy
  • 7,885
  • 5
  • 55
  • 61
  • Don't [**this answer**](https://stackoverflow.com/a/14919756/2341603) and [**this answer**](https://stackoverflow.com/a/36314992/2341603) from the very question you linked cover that? – Obsidian Age Oct 31 '17 at 03:55
  • I've been known to find ways to avoid jQuery myself - but this is an example of something you probably want to use it for... Assuming you actually asking for a way to do it without using an external library, most implementations we could give you would be incomplete and not work across all browsers. – Shadow Oct 31 '17 at 03:55
  • 4
    @ObsidianAge answer here for reputation. I asked this question because we deserve a top answer that doesn't use jQuery. Skimming through the jQuery answers sucks. – Andy Oct 31 '17 at 03:56
  • 1
    @Andy -- You already have an answer in that question though; if your problem was resolved beforehand, why ask the question? – Obsidian Age Oct 31 '17 at 03:57
  • @ObsidianAge to help other people who aren't using jQuery avoid reading through jQuery BS to find the answer. They can simply search for "upload a file without jQuery" and be more likely to find this question, once it gets enough upvotes. – Andy Oct 31 '17 at 03:58
  • 1
    Hi you should learn what actually jQuery does under the cover to upload files. Idea is to create formData, append file in formData and then send ajax (XMLHttpRequest) to server to upload the file or you can wrap it in iframe and post the formData from iframe to upload your files. – Muhammad Jahanzeb Oct 31 '17 at 03:59
  • @MuhammadZaib what do you have against there being a separate question with a top answer that doesn't involve jQuery? That is why I asked this, regardless of the fact that I can, with effort, find the answer I need already. – Andy Oct 31 '17 at 04:02
  • 1
    @Andy I believe what I replied doesn't involve any kind of jQuery. – Muhammad Jahanzeb Oct 31 '17 at 04:04
  • Then why didn't you actually post it as an answer, instead of telling me I should learn about how jQuery does it instead of just learning how to do it from first principles? – Andy Oct 31 '17 at 04:06
  • See [this answer](https://stackoverflow.com/a/14919756/2341603) or [this answer](https://stackoverflow.com/a/36314992/2341603) to the original question. – Andy Oct 31 '17 at 04:11
  • @ObsidianAge please read https://meta.stackoverflow.com/questions/290768/deliberately-opening-duplicate-questions-as-search-targets – Andy Oct 31 '17 at 04:11
  • 1
    At the bottom of this MDN tutorial (https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications) is an example of uploading a file using the `File` object and `XMLHttpRequest`. An even simpler way (without JavaScript at all) is to do it using an HTML form with a post method. – david25272 Oct 31 '17 at 04:21
  • 8
    How can a question of "how to do x *without* jquery?" be an exact duplicate of a question "how to do x *with* jquery?" ???? – Roddy of the Frozen Peas Oct 31 '17 at 13:37
  • At the time that other question didn't say "with jQuery" in the title, but it did specifically ask for a jQuery solution. – Andy Oct 31 '17 at 14:17
  • 1
    **Note:** this answer is being discussed on Meta - [How can we make it easier to find non-jQuery answers](https://meta.stackoverflow.com/q/358666/2756409) – TylerH Oct 31 '17 at 14:36

1 Answers1

-1

The oldest established way to do this is by making the <form> target a hidden <iframe> element by adding target="<name of iframe>" to the <form> element. When you call form.submit() in JavaScript, it will load the response in the target <iframe>:

<form id="uploadForm" action="/upload" method="post" encType="multipart/form-data" target="asyncFrame">
  <iframe id="asyncFrame" name="asyncFrame" height="0" width="0" frameborder="0"></iframe>
  <input type="file" id="file" name="file" accept=".csv" />
  <input type="text" name="comment" />
  <button type="submit">Upload</button>
</form>

<script>
  var iframe = document.getElementById('asyncFrame');

  function handleLoad() {
    console.log('response:', iframe.contentWindow.document.body.innerText);
  }
  iframe.addEventListener('load', handleLoad);
</script>

The most awkward thing about this approach is there is no way to get the status code of the response, and no standard way (as far I can tell) to determine if the request failed. You will have to inspect the response body (iframe.contentWindow.document.body.innerText) to determine if there was an error (if you are posting to your own server, luckily, you can ensure that the response body contains sufficient information, but if it is a 3rd-party server, you may be out of luck).

Andy
  • 7,885
  • 5
  • 55
  • 61