15

Suppose we have the following HTML file:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test iframe download</title>
<script type="text/javascript">

var init = 0;

function download() {
  document.getElementById("dload_frame").src = "http://example.com/dload.py";
}

function alert() {
  if (init == 0) {
    init = 1;
  }
  else {
    document.getElementById("alert_span").innerHTML = "Got it!";
  }
}

</script>
</head>
<body>

  <span id="alert_span">Main content.</span><br/>
  <input type="button" value="Download" id="btn" onclick="download()" />
  <iframe id="dload_frame" src="http://404.com/404" onload="alert()"> </iframe>

</body>
</html>

Now, if the URL to which iframe's src is being rewritten to (in this case - "http://example.com/dload.py") returns HTML, no problem: the onload event fires, the span's contents are replaced, everybody's happy.

However, if the content type of the file returned by the URL is set to something that forces the browser to open the save file dialog, the iframe's onload event never fires.

Is there any workaround? Using iframes isn't necessary, the desired behavior is to launch a callback after the browser begins downloading the supplied file.

dpq
  • 9,028
  • 10
  • 49
  • 69
  • You can try to fetch the file using ajax and then create `a` tag (link) with data URI and click on it, but I didn't test it with big files. – jcubic Feb 11 '18 at 15:37

5 Answers5

1

I have encountered the same problem as this: Here is my work-around, please see if it works for you:

<script>
 function download(){
    var url = 'http://example.com/dload.py';
    var htm = '<iframe src="' + url +'" onload="downloadComplete()"></iframe>';
    document.getElementById('frameDiv').innerHTML = htm;
 }
</script>

<div style="display:none" id="frameDiv">
</div>
<button onclick="download()">download file</button>

As far as I can remembered iframe's onload event fires only once. Setting another value for src attribute will not cause the onload event to fire again.

jerjer
  • 8,694
  • 30
  • 36
  • Very clever! Thank you. It doesn't work in Chrome, but at least in Firefox it works, and works multiple times, since every time it's actually a new iframe that fires the onload event, since you overwrite innerHTML. – dpq Oct 07 '09 at 10:11
  • I am glad it worked for you, I haven't tested it on Chrome though. – jerjer Oct 08 '09 at 12:53
  • This appeared to work for a similar issue that I had - as long as Firebug was running. When I tried in Firefox 2 or 3 without Firebug, all of a sudden the onload wouldn't fire. Anyone know where the difference is? – justkt Mar 16 '10 at 17:08
  • 1
    Does not work in Chrome: http://stackoverflow.com/questions/13952942/iframe-readystate-does-not-work-in-chrome – anmarti Dec 19 '12 at 16:20
0

My solution after many different approaches to get this working across ff ie safari and chrome was not have a 2 step download.

the original JS request to create an iframe loads a src that would normally have loaded the pdf However, the src now loads a page with yet another iframe inside of it, which now contains the url of the pdf. in the html response I trigger the onload and also a catchall setTimeout funciton which calls my response on window.parent.window.handlerfunction which my onload on the top iframe would have been. The result is a PDF download and a trigger on the top level parent of the handler function that works across the browsers since it no longer relies on detecting an actual iframe load but rather relies on supported parent/child window relationships.

hope this helps someone who was also stuck

Rulian
  • 17
  • 1
  • This detects when the outer-iframe HTML loads, obviously. It does NOT actually detect the PDF file download. (Though I guess it does give you the option of checking that the requested PDF exists, in the outer iframe's server-side script). – Doin Jul 18 '19 at 17:21
0

I have the same problem, onLoad handler is only fire when the content change. If you download a file. If you delete HTTP header to print file content on iframe, the onload is correctly fire.

0

You can check iframe readyState property repeatedly after short time intervals until it gets completed.

function iframe_onload(iframe_id, js) {
    var iframe = document.getElementById(iframe_id);
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

    if (iframeDoc.readyState == 'complete') {
        eval(js)
        return;
    }

    window.setTimeout('iframe_onload("' + iframe_id + '",`' + js + '`);', 100);
}
plavozont
  • 807
  • 9
  • 17
  • 1
    I have php base download and after first flush the data is send to the browser and the state is marked as complete even that download is still in progress. – jcubic Feb 11 '18 at 17:43
-1

You might need help of jquery for this, for instance you can do this:

$.get('http://example.com/dload.py',{},function(result){
   $('alert_span').html(result);//or some content
});
jerjer
  • 8,694
  • 30
  • 36
  • 3
    No, this won't work. An asynchronous call will save the returned value into the result variable and pass it to the callback function, instead of opening a save dialog. – dpq Oct 06 '09 at 11:52