Eugene Yu
Eugene Yu

Reputation: 3958

Download JSON object as a file from browser

I have the following code to let users download data strings in csv file.

exportData = 'data:text/csv;charset=utf-8,';
exportData += 'some csv strings';
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

It works just fine that if client runs the code it generates blank page and starts downloading the data in csv file.

So I tried to do this with JSON object like

exportData = 'data:text/json;charset=utf-8,';
exportData += escape(JSON.stringify(jsonObject));
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

But I see only a page with the JSON data displayed on it, not downloading it.

I went through some research and this one claims to work but I don't see any difference to my code.

Am I missing something in my code?

Thanks for reading my question:)

Upvotes: 263

Views: 323058

Answers (16)

mlimper
mlimper

Reputation: 5250

This is how I solved it for my application:

HTML: <a id="downloadAnchorElem" style="display:none"></a>

JS (pure JS, not jQuery here):

var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(storageObj));
var dlAnchorElem = document.getElementById('downloadAnchorElem');
dlAnchorElem.setAttribute("href",     dataStr     );
dlAnchorElem.setAttribute("download", "scene.json");
dlAnchorElem.click();

In this case, storageObj is the js object you want to store, and "scene.json" is just an example name for the resulting file.

This approach has the following advantages over other proposed ones:

  • No HTML element needs to be clicked
  • Result will be named as you want it
  • no jQuery needed

I needed this behavior without explicit clicking since I want to trigger the download automatically at some point from js.

JS solution (no HTML required):

  function downloadObjectAsJson(exportObj, exportName){
    var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
    var downloadAnchorNode = document.createElement('a');
    downloadAnchorNode.setAttribute("href",     dataStr);
    downloadAnchorNode.setAttribute("download", exportName + ".json");
    document.body.appendChild(downloadAnchorNode); // required for firefox
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
  }

Edit: If you'd like to format the JSON with some whitespace for better readability, you can use the additional parameters of the stringify function to do so:

  JSON.stringify(exportObj, null, 2)

See JSON.stringify on MDN, thanks TryingToImprove for the tip!

Upvotes: 439

Nam Do
Nam Do

Reputation: 113

function downloadJsonFile(data, filename) {
   // Creating a blob object from non-blob data using the Blob constructor
   const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
   const url = URL.createObjectURL(blob);
   // Create a new anchor element
   const a = document.createElement('a');
   a.href = url;
   a.download = filename || 'download';
   a.click();
   a.remove();
}

You can easily auto download file with using Blob and transfer it in first param downloadJsonFile. filename is name of file you want to set.

Upvotes: 9

Blaiz
Blaiz

Reputation: 447

Even simpler for modern browsers, combining the answers from user993683 and Abido:

<a
  href={URL.createObjectURL(
    new Blob([JSON.stringify(objectToDownload)], { type: "text/json" })
  )}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

Assuming the data isn't that big, otherwise it'll slow down the page and in that case it's better to lazily generate the data only when the user clicks on the link.

Upvotes: 1

acute_triceratops
acute_triceratops

Reputation: 101

Here's a simple version adapted from @Mohammed/@Maia working in modern browsers:

function saveAsFile(filename, data) {

    const blob = new Blob([JSON.stringify(data)]);
    const link = document.createElement("a");
    link.download = filename;
    link.href = window.URL.createObjectURL(blob);
    link.click()

};

Which can be used as

saveAsFile('posts.json', posts)

Upvotes: 5

Jonathan Alkalay
Jonathan Alkalay

Reputation: 1

const exportToJson = (data: {}) =>{

const link = document.createElement("a");
link.href = data:text/json;charset=utf8,${encodeURIComponent(JSON.stringify(data))}; link.download = 'example.json'; link.click(); }

Make sure to clean up the the created link after if you don't want a random element that does nothing.

Upvotes: 0

MSOACC
MSOACC

Reputation: 3675

ES6+ version for 2021; no 1MB limit either:

This is adapted from @maia's version, updated for modern Javascript with the deprecated initMouseEvent replaced by new MouseEvent() and the code generally improved:

const saveTemplateAsFile = (filename, dataObjToWrite) => {
    const blob = new Blob([JSON.stringify(dataObjToWrite)], { type: "text/json" });
    const link = document.createElement("a");

    link.download = filename;
    link.href = window.URL.createObjectURL(blob);
    link.dataset.downloadurl = ["text/json", link.download, link.href].join(":");

    const evt = new MouseEvent("click", {
        view: window,
        bubbles: true,
        cancelable: true,
    });

    link.dispatchEvent(evt);
    link.remove()
};

If you want to pass an object in:

saveTemplateAsFile("filename.json", myDataObj);

Upvotes: 44

Gautham
Gautham

Reputation: 876

You could try using:

  • the native JavaScript API's Blob constructor and
  • the FileSaver.js saveAs() method

No need to deal with any HTML elements at all.

var data = {
    key: 'value'
};
var fileName = 'myData.json';

// Create a blob of the data
var fileToSave = new Blob([JSON.stringify(data)], {
    type: 'application/json'
});

// Save the file
saveAs(fileToSave, fileName);

If you wanted to pretty print the JSON, per this answer, you could use:

JSON.stringify(data,undefined,2)

Upvotes: 52

zb&#39;
zb&#39;

Reputation: 8059

If you prefer console snippet, raser, than filename, you can do this:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))

Upvotes: 6

Brad
Brad

Reputation: 8698

I recently had to create a button that would download a json file of all values of a large form. I needed this to work with IE/Edge/Chrome. This is what I did:

function download(text, name, type)
    {
        var file = new Blob([text], {type: type});
        var isIE = /*@cc_on!@*/false || !!document.documentMode;
        if (isIE)
        {
            window.navigator.msSaveOrOpenBlob(file, name);
        }
        else
        {
            var a = document.createElement('a');
            a.href = URL.createObjectURL(file);
            a.download = name;
            a.click();
        }
     }

download(jsonData, 'Form_Data_.json','application/json');

There was one issue with filename and extension in edge but at the time of writing this seemed to be a bug with Edge that is due to be fixed.

Hope this helps someone

Upvotes: 18

Abido
Abido

Reputation: 802

React: add this where you want in your render method.

• Object in state:

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.state.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

• Object in props:

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.props.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

className and style are optional, modify the style according to your needs.

Upvotes: 6

user993683
user993683

Reputation:

Simple, clean solution for those who only target modern browsers:

function downloadTextFile(text, name) {
  const a = document.createElement('a');
  const type = name.split(".").pop();
  a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
  a.download = name;
  a.click();
}

downloadTextFile(JSON.stringify(myObj), 'myObj.json');

Upvotes: 33

maia
maia

Reputation: 4360

The following worked for me:

/* function to save JSON to file from browser
* adapted from http://bgrins.github.io/devtools-snippets/#console-save
* @param {Object} data -- json object to save
* @param {String} file -- file name to save to 
*/
function saveJSON(data, filename){

    if(!data) {
        console.error('No data')
        return;
    }

    if(!filename) filename = 'console.json'

    if(typeof data === "object"){
        data = JSON.stringify(data, undefined, 4)
    }

    var blob = new Blob([data], {type: 'text/json'}),
        e    = document.createEvent('MouseEvents'),
        a    = document.createElement('a')

    a.download = filename
    a.href = window.URL.createObjectURL(blob)
    a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
    e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
    a.dispatchEvent(e)
}

and then to call it like so

saveJSON(myJsonObject, "saved_data.json");

Upvotes: 24

jbcdefg
jbcdefg

Reputation: 307

This would be a pure JS version (adapted from cowboy's):

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

var a = document.createElement('a');
a.href = 'data:' + data;
a.download = 'data.json';
a.innerHTML = 'download JSON';

var container = document.getElementById('container');
container.appendChild(a);

http://jsfiddle.net/sz76c083/1

Upvotes: 29

Eugene Yu
Eugene Yu

Reputation: 3958

Found an answer.

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');

seems to work fine for me.

** All credit goes to @cowboy-ben-alman, who is the author of the code above **

Upvotes: 45

robertjd
robertjd

Reputation: 4913

The download property of links is new and not is supported in Internet Explorer (see the compatibility table here). For a cross-browser solution to this problem I would take a look at FileSaver.js

Upvotes: 5

minimulin
minimulin

Reputation: 41

Try to set another MIME-type: exportData = 'data:application/octet-stream;charset=utf-8,';

But there are can be problems with file name in save dialog.

Upvotes: 2

Related Questions