2019-11-07
|~2 min read
|367 words
I thought this was pretty cool. Imagine you want to create a file programmatically and allow a user to download it.
For the sake of this example, let’s assume that by the time we try to download the file (i.e. click the button), we’ve already stored the data in a Blob
.1
<body>
<!-- … -->
<button id="download">download</button>
</body>
<script>
// handleDownload to go here…
document.getElementById("download").addEventListener("click", handleDownload)
</script>
We don’t know which file they’re going to create in advance, so we can’t prepare it on page load (nor would we want to in the event that the user is satisfied with the web view).
One way to solve this is to create a new Element on the DOM, attach a few key properties to it, and then remove it once done.
That might look something like this:
const downloadFile = (blob, fileName) => {
const temporary = document.createElement("a") // create a temporary a tag element
document.body.appendChild(temporary) // attach it to the body
const url = window.URL.createObjectURL(blob) // generate a URL
temporary.href = url // attach the URL to the temporary element
temporary.download = fileName // assign a name to download property
temporary.click() // "click" the temporary element
setTimeout(() => {
window.URL.revokeObjectURL(url) // remove the generated url
document.body.removeChild(temporary) // remove the temporary object from the DOM
}, 0) // I don’t believe the setTimeout is strictly necessary, but _may_ help if `click()` hangs
}
Note that I am creating temporary urls which is then attached to the anchor tag’s href
. I say temporary because the URL created from createObjectURL
is automatically removed when the document is unloaded (however, for memory management purposes, it’s recommended that the URL is manually removed when safe to do so — this is why I have revokeObjectURL
).2
While I’m obviously aware that you can download files from the internet, I don’t have a lot of experience exploring the Window or Document APIs. As a result, this felt like a pretty simple solution to a problem that’s bound to come up.
For an interactive version (in React), I put together a CodeSandBox to play with.
Blob
MDN pagecreateObjectURL
MDN pageHi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!