paint-brush
Downloading Data as a File with Alpine.jsby@raymondcamden
1,525 reads
1,525 reads

Downloading Data as a File with Alpine.js

by Raymond CamdenDecember 26th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In the original article, I first demonstrated downloading a JSON file. But as most humans don't speak JSON, I then used Papa Parse to convert it to CSV. I'm going to follow the same flow for this update.
featured image - Downloading Data as a File with Alpine.js
Raymond Camden HackerNoon profile picture

As my readers know, I've been updating some of my earlier Vue.js examples to demonstrate how they would work with Alpine.js. Normally I post these "conversions" when I see one of the Vue posts pop up in my stats. Today I noticed this entry was "trending" - Vue Quick Shot - Downloading Data as a File. I thought it would be a great candidate for showing an Alpine version. Let's take a look.


While I won't repeat everything from the previous post, I'll quickly cover how it worked. First, it makes use of the download attribute of the anchor tag. This will take a normal link operation and instead ask the browser to download the resource at the URL. To do this with client-side data, you can create an anchor tag with createElement, set it to point to your data, and then emulate a click event. I used this a few days ago in an Eleventy article: Adding Download Support in an Eleventy Site.


In the original article, I first demonstrated downloading a JSON file. But as most humans don't speak JSON, I then used Papa Parse to convert it to CSV. I'm going to follow the same flow for this update.

First Version - Downloading JSON Data

For the first version, we're going to look at a tabular set of cats. I will not make you scroll past the gratuitous picture of a cat on a table. Heh, I lie:


Cat on a table


Ok, so our data:


"cats":[
	{"name":"Alese", "gender":"female", "age": 10},
	{"name":"Sammy", "gender":"male", "age": 12},
	{"name":"Luna", "gender":"female", "age": 8},
	{"name":"Cracker", "gender":"male", "age": 7},
	{"name":"Pig", "gender":"female", "age": 6}
]


The application begins by simply rendering this into a table. (Not a sortable or paginated one, but check out my other Alpine.js posts for examples of that.) I started off with this HTML:


<div x-data="app">
	<table>
		<thead>
			<tr>
				<th>Name</th>
				<th>Gender</th>
				<th>Age</th>
			</tr>
		</thead>
		<template x-for="cat in cats">
			<tr>
				<td x-text="cat.name"></td>
				<td x-text="cat.gender"></td>
				<td x-text="cat.age"></td>
			</tr>
		</template>
	</table>
</div>


Alpine is used to loop over the cats array. Here's the initial JavaScript:


document.addEventListener('alpine:init', () => {
  Alpine.data('app', () => ({
	cats:[
      {name:"Alese", gender:"female", age: 10},
      {name:"Sammy", gender:"male", age: 12},
      {name:"Luna", gender:"female", age: 8},
      {name:"Cracker", gender:"male", age: 7},
      {name:"Pig", gender:"female", age: 6}
      ]		
  }))
});


Now I'm going to add a download button that will trigger the download process:


<button @click="download">Download</button>


I then added my handler. This code is a bit simpler than the previous version which added to anchor to the DOM, invisibly, and then clicked.


download() {
	let text = JSON.stringify(this.cats);
	let filename = 'cats.json';
	let element = document.createElement('a');
	element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text));
	element.setAttribute('download', filename);
	element.click();
}

If you read my previous article involving Eleventy and downloads, the biggest difference here is creating the data URL string that has the original data encoded into a string. You can test this version yourself here:


Second Version - Downloading CSV

For the next version, we just need to convert the JSON data to CSV. Once again I'll use Papa Parse as it makes this trivial. Instead of


let text = JSON.stringify(this.cats);


We can use:


let text = Papa.unparse(this.cats);


I then made two more changes. First, the filename:


let filename = 'cats.csv';


And then the mime-type:


element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(text));


That's literally the entire change. Now when clicking download you get a CSV that can be opened in Excel. My previous post had a screenshot of that but as this was before you could use Dark mode in Office, I figured I'd update it with a new one:




Here's the entire example:

Also published here.