Saving / Loading files with Javascript (from the browser)

Something I was experimenting with on a project recently was saving and loading JSON strings to file from the browser. It's something that immediately seems obvious and simple, but in all my years doing frontend web development it's not something I've tried before.

I'll show how I achieved it in jQuery, you can migrate the idea over to vanillaJS if needed, but please bear in mind this will only work in IE10+.

Saving

Let's start with saving a file.

Firstly we'll need a string of JSON to store. This is achieved simply by taking whatever text you have and parsing it as JSON which might be familiar to anyone who does AJAX transactions.

// object we want to save
var myObject = { name: "simon", surname: "goellner" };  
// convert to json string
var myJSON = JSON.stringify( myObject );  

So now we have our text to save, the idea is that we create a download link, and then trigger a click on it to force the download process.

// create a link DOM fragment
var $link = $("<a />");  
// encode any special characters in the JSON
var text = encodeURIComponent( myJSON );

// <a download="filename.txt" href='data:application/octet-stream,...'></a>
$link
  .attr( "download", "filename.txt" )
  .attr( "href", "data:application/octet-stream," + text )
  .appendTo( "body" )
  .get(0)
  .click()

That's it, super simple. How you generate the contents, and what they will be depends wholly on your project and content. The filename and extension are completely up to you and can/should be generated.


Loading

Loading is a little more complicated, but it's still a fairly simple endeavour.

The main idea is that we provide a <input /> field to load the file, use the FileReader() api to read the file contents and store it to a variable.

html

<!-- the html element we listen to -->  
<input id="fileField" type="file" />  

javascript

With the field created in HTML, we need only now to reference it and listen to a change event.

Firstly we set up references to the file <input /> field, and the FileReader API.

// get the file field
var $field = $("#fileField");  
// create a new FileReader object
var reader = new FileReader();  

Now we create a load event listener to do our work. The file contents are eventually passed to this onload event; accessible through the event.target.result property.

// when the file has finished reading,
// store it's contents to a variable (async)
reader.onload = function( ev ) {

   var contents = JSON.parse( decodeURIComponent( ev.target.result ) );
   // execute follow-up work here...

};

Then we set up a change event listener on the file input. Once the field changes we read the contents of the file selected and store them to a variable called contents.

// when it changes (ie: user selects a file)
$field.on("change", function() {

    // get the file item from the input field
    var file = this.files[0];
    // read the file as text
    reader.readAsText( file );
    // and then then load event will trigger ...

});

I hope this is helpful, please reference MDN for any advanced information, the FileReader() API is super useful and powerful!