user2752635 user2752635 - 2 months ago 7
Javascript Question

Firefox a.click won't fire without a breakpoint

I'm working on a project where we have an AJAX call which responds width a blob containing an excel file. I want the code to open the file as a download when I get the response. Here is the callback:

var blob = new Blob([response.data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
var objectUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
var header = response.headers("Content-Disposition");
a.download = header.substring(header.indexOf("filename=") + "filename=".length);
a.href = objectUrl;
document.body.appendChild(a);
console.debug("Clicking a tag");
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(objectUrl);


This code works fine in chrome but in firefox nothing happens when a.click() fires. The debug statement prints so I know that the callback is happening. Also, for some reason, if I put a breakpoint on
a.click()
it works perfectly.

Can someone explain why the click only works in debug mode?

Answer

Firefox has a couple of safeguards or just odd behaviors around things like this. I don't know the derivation, but yielding back to the browser for a moment before doing the click usually clears it up:

// ...
a.href = objectUrl;
document.body.appendChild(a);
setTimeout(function() {
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(objectUrl);
}, 0);
// ...

Note that code following the setTimeout will run before the content of the setTimeout does.

You might even need two:

// ...
a.href = objectUrl;
document.body.appendChild(a);
setTimeout(function() {
    a.click();
    setTimeout(function() {
        document.body.removeChild(a);
        window.URL.revokeObjectURL(objectUrl);
    }, 0);
}, 0);
// ...