5

I've got a problem: I would like to catch a moment when the Save File dialog is closed or my csv file generated on the server is loaded (to hide a spinner for loading). I know there is no such event in the Javascript. I definitely don't want to add cookies for such a minor issue on the backend so I would like to implement another workaround. The only way out I see is iframe but as far as I can see event listeners like onload doesn't work in case of attachment header in Chrome at least. I've also tried to implement a kind of timer checking for iframe status but it worked right after request for file was sent. File is generated on server in some seconds (10-20) so this solution doesn't fit my goals.

I'm using Angular on the frontend so any solution compatible (vanilla JS, jQuery, Angular itself) will be a great help for me. Hope to get any. Thank you, guys!

Dmitry Senkovich
  • 5,521
  • 8
  • 37
  • 74
  • Possible duplicate of [Detect when user accepts to download a file](http://stackoverflow.com/questions/41334881/detect-when-user-accepts-to-download-a-file), [How to solve Uncaught RangeError when download large size json](http://stackoverflow.com/questions/39959467/how-to-solve-uncaught-rangeerror-when-download-large-size-json) – guest271314 Dec 27 '16 at 16:11
  • @guest271314 Actually, no, it is no. I saw the answer you show but it couldn't help me. – Dmitry Senkovich Dec 27 '16 at 16:15
  • _"I saw the answer you show but it couldn't help me"_ What do you mean? The first link checks for file being saved by user; the second link will provide actual moment file has completed downloading to browser after _N_ seconds or minutes. _"I would like to catch a moment when the Save File dialog is closed or my csv file generated on the server is loaded (to hide a spinner for loading)."_ The second link should answer present Question. What is requirement which is not satisfied by first or second link? – guest271314 Dec 27 '16 at 16:17
  • @guest271314 I haven't seen the second answer, sorry, but the first one didn't help me. For example, digging deeper into the first answer on the first link needs cookie on a server. Others doesn't fit as well (I listed points in the question) but I don't think it is a good idea to list all the answers on the first link. Btw, thanks for the second link, I will checkout the answers on it! – Dmitry Senkovich Dec 27 '16 at 16:28
  • Note, the approach at first link does not require a cookie. The second link should meet requirement described at Question. You could combine the two solutions to both determine when file has completed being loaded and when user downloads or does not download file to user filesystem. – guest271314 Dec 27 '16 at 16:30
  • @guest271314 Sorry, I meant the second one. Also, the approaches from the second link doesn't seem to be helpful as I need not to load csv content into JS but download file – Dmitry Senkovich Dec 27 '16 at 16:32
  • _"Also, the approaches from the second link doesn't seem to be helpful as I need not to load csv content into JS but download file"_ The second link does offer download of file when file has completed being fetched from server, including monitoring progress of bytes of file received from server. – guest271314 Dec 27 '16 at 16:33
  • @guest271314 Have you noticed this line 'json += decoder.decode(result.value);'? I suppose this one is buffer for file being downloaded. This buffer is located in RAM as any other variable. My csv file can be very large so it cannot be downloaded this way. – Dmitry Senkovich Dec 27 '16 at 16:45
  • _"My csv file can be very large so it cannot be downloaded this way."_ The file requested at linked Question is 189MB. If monitoring progress of file download is not necessary, and you only need to hide and show an element you can omit `ReadableStream` portion of approach and use `fetch()`, `Response.blob()` directly. `fetch(url) .then(response => response.blob()) .then(blob => {let url = URL.createObjectURL(blob); // download here using element})` – guest271314 Dec 27 '16 at 16:48
  • @guest271314 But this code contains 'response' variable that is csv data itself i.e. it is stored in RAM – Dmitry Senkovich Dec 27 '16 at 16:57
  • Not certain what you mean? You can call `Blob.prototype.close()` to free RAM [File API 4.3.2. The close method](https://w3c.github.io/FileAPI/#close-method) _"If the context object has an entry in the Blob URL Store, remove the entry that corresponds to the context object."_. How are you currently processing download of file? Can you include current `javascript` approach at Question which does not use RAM? You can alternatively substitute `XMLHttpRequest` for `fetch` to return same result. – guest271314 Dec 27 '16 at 17:00
  • @guest271314 For example, this approach will load generated file directly: 'var csvUrl = document.createElement('a'); csvUrl.href = url; csvUrl.download = "csv_filename"; csvUrl.click();' – Dmitry Senkovich Dec 27 '16 at 17:04
  • _"For example, this approach load generated file directly"_ Not clear what you are asking. Are you trying to get and display the file, or offer file for download; or both? How are you currently handling requesting and offering file for download which is substantially different that approach at linked Question? What is issue with current approach? – guest271314 Dec 27 '16 at 17:06
  • @guest271314 I provided a code snapshot above. Just pressed 'enter' occasionally:) – Dmitry Senkovich Dec 27 '16 at 17:10
  • As you noted, there is currently no `DOM` event, which am aware of, which fires when `Save file` UI closes. You can use `focus` event to try to determine when `window` regains focus following closing of `Save file` dialog. `csvUrl.click(); window.onfocus = function () { document.body.removeChild(a); window.onfocus = null; // remove spinner here }` – guest271314 Dec 27 '16 at 17:11
  • @guest271314 That's an interesting idea. Sounds like a solution I was looking for. Could you please provide some more details if you'd like to and make an answer? I will try right now. – Dmitry Senkovich Dec 27 '16 at 17:12
  • @guest271314 this code snapshot assumes the Save File dialog appears right after the link gets clicked. But it is not that way as at first file is being generated on a server. All this time window has focus I think. – Dmitry Senkovich Dec 27 '16 at 17:17
  • There is no set of events which are fired at each step of the process. The alternative is to use `XMLHttpRequest` or `fetch` to retrieve file. With `fetch` you can read the bytes and determine with more accuracy the amount of bytes received, then offer file for download. Generally, the `Save file` UI dialog appears momentarily. Workarounds for the lack of existing standardized methods to monitor the progress of files offered for download, or whether user actually downloaded file. Not certain what answer you are expecting given that no standardized approaches exist which address this topic? – guest271314 Dec 27 '16 at 17:26

1 Answers1

1

There is no DOM event, which am aware of here, which is fired when Save file UI dialog is opened or closed.

You can try utilizing focus event to catch when the Save file dialog is closed and window regains focus after calling .click() on <a> element having download attribute set, though the approach is not completely reliable.

// append or display spinner element here
var csvUrl = document.createElement("a"); 
csvUrl.href = url; 
csvUrl.download = "csv_filename"; 
csvUrl.click();
window.onfocus = function () { 
  document.body.removeChild(csvUrl); 
  // remove or hide spinner element here 
  window.onfocus = null; 
}
guest271314
  • 1
  • 15
  • 104
  • 177