6

I know there have been similar topics, but I haven't found exactly what I am looking for.

The requirement is, to generate and download a file with a given name and extension when clicking on an element (e.g. button). Generating this file is expensive to compute, so I cannot compute it beforehand and add it to the href attribute of a link/<a>, like proposed in many answers.

For example in this fiddle

var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));

$('<a href="data:' + data + '" download="data.json">download JSON</a>').appendTo('#container');

I also found this answer, but apparently it is not possible to specify a filename here.

So I was wondering if this is even possible or might be forbidden due to security limitations (would make sense)?

Robin
  • 3,512
  • 10
  • 39
  • 73
  • 2
    you can use [my download.js lib](https://github.com/rndme/download/) to easily create dynamic content pre-named files client-side. – dandavis Aug 23 '17 at 05:38
  • @dandavis I just tried your lib. It works perfect, thanks! Feel free to add it as an answer below. – Robin Aug 23 '17 at 06:50

3 Answers3

21

Here is a nice download function that takes the filename and contents as the inputs and automatically downloads it.

function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
}

// Start file download.
document.getElementById("dwn-btn").addEventListener("click", function(){
    // Generate download of hello.txt file with some content
    var text = document.getElementById("text-val").value;
    var filename = "hello.txt";
    
    download(filename, text);
}, false);
<textarea id="text-val" rows="4">This is the content of my file</textarea><br/>
<input type="button" id="dwn-btn" value="Download dynamically generated text file"/>
johnpyp
  • 867
  • 2
  • 7
  • 13
  • Thanks for the answer, but this is essentially the same as the fiddle I posted above. You fill the `a` tag with a href and download value and then the user needs to click on it. I only want one click. – Robin Aug 23 '17 at 05:31
  • Alright, I'll edit my answer with a different solution that I think fits. – johnpyp Aug 23 '17 at 05:34
  • Ok, edited. This will automatically generate it completely in javascript. Edit: I noticed in your post you said adding editing the href was bad. This seems to work correctly and I don't understand why you don't like this method. – johnpyp Aug 23 '17 at 05:37
5

You can create data dynamically using javascript.

Below is code what I'm using for the same.

function downloadFile() {
    var obj = {a: 123, b: "4 5 6"};
    var filename = "download.json";
    var blob = new Blob([JSON.stringify(obj)], {type: 'text/plain'});
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(blob, filename);
    } else{
        var e = document.createEvent('MouseEvents'),
        a = document.createElement('a');
        a.download = filename;
        a.href = window.URL.createObjectURL(blob);
        a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':');
        e.initEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        a.dispatchEvent(e);
    }
}

And html code is

<input type="button" onclick="downloadFile();" value="Download">

Hope it'll help you.

ELITE
  • 5,815
  • 3
  • 19
  • 29
2

For those who searched this question:

There are two ways to generate and send files in Javascript, URL or BLOB, sample code was shown in above answers.

You may be concerned about whether the maximum length of the URL is suitable for passing files, that's okay, as summarized in this question (stackoverflow.com), modern browsers other than IE support URLs of sufficient length (from 2GB to nearly infinite, and the standard also specifies that at least 8000 bytes in length needs be supported).

Of course, you can also choose a third-party library to implement the feature such as file-saver (npmjs.com).

boholder
  • 100
  • 2
  • 6