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.
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:
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:
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.