CSV generation from JSON in Svelte
Tags: svelte, tutorial, javascript, compiler
Published: 2019-12-16 04:01:26

---
title: CSV generation from JSON in Svelte
published: true
description: Generate CSV without third party library and fully supported by all browser and mobile devices.
tags: Svelte, tutorial, JavaScript, compiler 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/9nlofmvbn3zol8mu4p0g.PNG
---

Svelte is the new big thing in the market and I decided to try one common use case i.e. CSV generation from JSON. For those who don't know svelte

"*Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.*"

There are several ways to setup Svelte project. You can read more about the many ways to get started here. For the purpose of this demo, we will be working with `degit` which is a software scaffolding tool. To start, run the following command:

```javascript
npx degit sveltejs/template svelte-CSV-demo
```

Now go inside the project directory using following command:

```javascript
cd svelte-CSV-demo
```

let's install the project dependencies using following command:

```javascript
npm install
```

Now our Svelte base project is ready. Let's start writing our code.

We have four part of our project
1. load the JSON from REST API
2. Integrate the JSON with template
3. Add style to project
4. CSV generation utility
5. End to End integration
6. Deploying to the web With [now](https://zeit.co/now)

If you are interested only in Code you can checkout the code from below URL
`https://github.com/karkranikhil/svelte-csv-demo`

**1. load the JSON from REST API** 
Go to `App.svelte` file and remove the existing code with the below code
```javascript
<script>
  import { onMount } from "svelte";

  let tableData = [];

  onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
    tableData = await res.json();
    console.log(tableData);
  });
 
</script>
```
As shown above, we have imported the `onMount` from svelte package. 
`onMount` is fired after the component is rendered. After that we have initialized the variable `tableData` with an empty array. 
Now we have defined the `onMount` function and within that we have used the async & await .
* `async` functions returns a promise.
* `async` functions use an implicit Promise to return its result. Even if you don’t return a promise explicitly `async` function makes sure that your code is passed through a promise.
* await blocks the code execution within the `async` function, of which it(await statement) is a part.

We have used *Fetch API* to get the JSON from the service. The Fetch API is a promise-based JavaScript API for making asynchronous HTTP requests in the browser. On successful calling of REST API we are storing the JSON in `tableData` and printing it in console.

Let'run the project and see the console. To start the project run the following command.

```javascript
npm run dev
```

once Above command run successfully navigate to http://localhost:5000/. 
Open your developer console and you will see the following output.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/sfdp7eyb0z2k7fpzw51t.PNG)

If you look at the above image we are able to get the data successfully. Now we will go to next step and will see how to integrate it with HTML markup


**2. Integrate the JSON with template**
Now we already have our API data in `tableData` variable. Now we will integrate the data using `#each` iterator. Add the following code to `App.svelte` below `script` tag
```html
<div class="container">
  <div class="header">
    <h1>CSV generation from JSON in Svelte</h1>
  </div>
  <div class="main">
    <table>
      <thead>
        <tr>
          {#each tableHeader as header}
            <th>{header}</th>
          {/each}
        </tr>
      </thead>
      <tbody>
        {#each tableData as item}
          <tr>
            <td>{item.userId}</td>
            <td>{item.id}</td>
            <td>{item.title}</td>
            <td>{item.body}</td>
          </tr>
        {/each}
      </tbody>
    </table>

  </div>
</div>
```
Above we have created the `div` with class `container` that hold two child one with `header` class another with `main` class. In `div` with `header` class we are only showing the header of our app. In `div` with `main` class we are creating  the table and within the table we are creating table header and table body using `#each` block. `#each` loops the data in markup.
We are using two loop one for header and another for the body. For table body we are using `tableData` that contains the REST API response and for header we are using the `tableHeader` variable that will create now under the `script` tag.
let's define the `tableHeader` below `tableData` and initializing it with the array of custom header keys as shown below.

```javascript
let tableHeader = ["User Id", "ID", "Title", "Description"];
```

Let's run the project again if it's stop otherwise go to browser and you will see the following output.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zodszgx9d3hbtj64lytt.PNG)



**3. Add style to project** 
I have define some CSS to make our page look better. you can use it by adding the `style` tag after the markup

```css
<style>
  .container {
    max-width: 1140px;
    margin: auto;
  }
  .header {
    display: flex;
    justify-content: space-between;
    display: flex;
    justify-content: space-between;
    background: orange;
    padding: 10px;
  }
  table {
    font-family: arial, sans-serif;
    border-collapse: collapse;
    width: 100%;
  }

  td,
  th {
    border: 1px solid #dddddd;
    text-align: left;
    padding: 8px;
  }

  tr:nth-child(even) {
    background-color: #dddddd;
  }
  button {
    border: none; /* Remove borders */
    color: white; /* Add a text color */
    padding: 14px 28px; /* Add some padding */
    cursor: pointer; /* Add a pointer cursor on mouse-over */
    background-color: #4caf50;
    height: fit-content;
  }
  h1 {
    margin: 0px;
  }
</style>
```
Now if you look at the output, it will look like as shown below

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/njc3ktwfpytkzhfjubfj.PNG)

**4.CSV generation Utility** 

Here is the key step in which we have wrote some Utility that will generate the csv based on some parameters. It works with all browser and even on all mobile phones.

So, let's create a new file `csvGenerator.js` inside the src folder and paste the below code in it.

```javascript
export const csvGenerator = (totalData,actualHeaderKey,headerToShow,fileName) => {
  let data = totalData || null;
  if (data == null || !data.length) {
    return null;
  }
  let columnDelimiter = ",";
  let lineDelimiter = "\n";
  let keys = headerToShow;
  let result = "";
  result += keys.join(columnDelimiter);
  result += lineDelimiter;
  data.forEach(function(item) {
    let ctr = 0;
    actualHeaderKey.forEach(function(key) {
      if (ctr > 0) result += columnDelimiter;
      if (Array.isArray(item[key])) {
        let arrayItem =
          item[key] && item[key].length > 0
            ? '"' + item[key].join(",") + '"'
            : "-";
        result += arrayItem;
      } else if (typeof item[key] == "string") {
        let strItem = item[key] ? '"' + item[key] + '"' : "-";
        result += strItem ? strItem.replace(/\s{2,}/g, " ") : strItem;
      } else {
        let strItem = item[key] + "";
        result += strItem ? strItem.replace(/,/g, "") : strItem;
      }

      ctr++;
    });
    result += lineDelimiter;
  });

  if (result == null) return;

  var blob = new Blob([result]);
  if (navigator.msSaveBlob) {
    // IE 10+
    navigator.msSaveBlob(blob, exportedFilenmae);
  } else if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
    var hiddenElement = window.document.createElement("a");
    hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(result);
    hiddenElement.target = "_blank";
    hiddenElement.download = fileName;
    hiddenElement.click();
  } else {
    let link = document.createElement("a");
    if (link.download !== undefined) {
      // Browsers that support HTML5 download attribute
      var url = URL.createObjectURL(blob);
      link.setAttribute("href", url);
      link.setAttribute("download", fileName);
      link.style.visibility = "hidden";
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  }
};

```
As shown above, we have created a function called csvGenerator. That takes four paramters as mentioned below

*totalData* - totalData is the JSON data to pass to CSV sheet
*actualHeaderKey* - This is the array of JSON key name that need to be used to pick up data from totalData
*headerToShow* - This is the array of custom name to show on header row of the csv file
*fileName* -Name of the file by which it get download with an extension of `.csv`

`csvGenerator` function will take the input and generate the CSV output by looping the data and adding comma to each value.

**5. End to End integration**

Till now we are ready with table and csvGenerator. Let's connect both together.
First we need to import the `csvGenerator` file to our `App.svelte`. Add the following line below the `onMount` import statement

```javascript
import { csvGenerator } from "./csvGenerator";
```

Now we need a handler that will get called on click of button from markup and call our utility `csvGenerator`. Add the following code below `onMount` function 

```javascript
function downloadHandler() {
let tableKeys = Object.keys(tableData[0]); //extract key names from first Object
csvGenerator(tableData, tableKeys, tableHeader, "svelte_csv_demo.csv");
}
```
As shown above, we have created a function called `downloadHandler` that will called on click of button and generate the CSV file of table data.

Let's create now a button on our template. Add the following code below the the h1 tag

```html
<button on:click={downloadHandler}>Download</button>
```

and run the project and you will see the below output on your browser.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0kkxxmoxqpbvrigeznps.PNG)


On click of download button it will download the CSV in your machine.

**4. Deploying to the web With [now](https://zeit.co/now)**


Install `now` if you haven't already:

```bash
npm install -g now
```

Then, from within your project folder:

```bash
cd public
now deploy --name svelte-csv-demo
```
`now` will deploy your code and generate a URL.

Deployed Url - https://svelte-csv-demo.karkranikhil.now.sh

Github - https://github.com/karkranikhil/svelte-csv-demo

---

## References

https://svelte.dev/