What are the steps to transform a blob into an xlsx or csv file?

An interesting feature of the application is the ability to download files in various formats such as xlsx, csv, and dat. To implement this, I have utilized a library called fileSaver.js.

While everything works smoothly for the dat/csv format, there seems to be an issue with the xlsx files being corrupted.

To troubleshoot this problem, I experimented with different conversion formats including:

  • utf8
  • base64
  • binary

Here's a snippet of how I implemented this:

// /* SERVER */ //
// Read data from file
fs.readFile(filePath, (err, data) {...})

// The API responds with the important parts "filename" & "data"
{"status":"ok","context":"writing the intermediate file","target":"/temp/","fileName":"name.xlsx","data":{"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]}}
// /* CLIENT */ //
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let read = buffer.toString('utf8')
let blob = new Blob([read])
FileSaver.saveAs(blob, fileName)

Answer №1

For those delving into this topic, here is my solution:

(Note that a more efficient solution for downloading a file would be to send the file in the API response with the header 'Content-disposition' or utilize Express for this purpose like this)

The backend (Node) operates as follows:

 fs.readFile(filePath, (err, data) => {
    if (err) {
      console.log(`-------- whoops error - read --------`)
      console.log(err)
      res.send({ status: `error`, context: `read the source file`, id: err.errno, code: err.code, message: err.message.replace(/\\/g, '/') })
    } else {
      res.send({ status: `ok`, context: `send data file`, target: target, fileName: fileName, data: data })
    } 
  })

Details:

  • target represents the path for the front end including the file name and extension (/path/name.ext)
  • fileName simply contains the name and extension (name.ext)
  • data is the information sent by readFile (
    {"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]}
    )

The frontend (React) functions like this:

fetch(targetUrl)
    .then(res => res.json())
    .then(res => {
      if (res.status !== `ok`) {
        this.setState({
          errorDlFile: true,
          errorDlFile_context: res.context,
          errorDlFile_id: res.id,
          errorDlFile_code: res.code,
          errorDlFile_message: res.message
        })
      } else {  
        const target = res.target
        const fileName = res.fileName
        const data = res.data
        const splitName = res.fileName.split('.')
        const format = splitName[splitName.length-1]

        // file saver blob solution
        let json = JSON.stringify(data)
        let buffer = Buffer.from(JSON.parse(json).data)
        let readUTF8 = buffer.toString('utf8')
        let blob = ''

        if (format === 'xlsx') {
          blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
        } else if (format === 'csv') {
          blob = new Blob([readUTF8], { type: 'application/vnd.ms-excel' })
        } else {
          blob = new Blob([readUTF8])
        }

        FileSaver.saveAs(blob, fileName)

      }
    })

Answer №2

@Hadock To download a file with a .csv extension, you must specify the type of file like this:

let blob = new Blob([csv], { type: 'application/vnd.ms-excel' });
instead of
let blob = new Blob([read])
And remember to include the filename with the extension (test.csv). I have also used a different plugin for excel files called exceljs. You can see a demo of it here: demo.

Answer №3

To convert JSON data to an Excel (.xlsx) file, you cannot directly save it in that format. However, you can achieve this by using a library such as 'sheetjs' ().

var sheet_name = filename;//"SheetJS";
var workbook = new Workbook(), worksheet = sheet_from_array_of_arrays(data);
/* add the worksheet to the workbook */
workbook.SheetNames.push(sheet_name);
workbook.Sheets[sheet_name] = worksheet;
var workbook_output = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'binary' });
saveAs(new Blob([s2ab(workbook_output)], { type: "application/octet-stream" }), filename + ".xlsx")

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Identifying when a fetch operation has completed in vue.js can be accomplished by utilizing promises

Currently, I am facing a dilemma in my Vue.js application. I am making an API call within the created() hook, but there are certain tasks that I need to trigger only after the API call has been completed. The issue is that this API call usually takes aroun ...

Creating an Add-in using the Excel JavaScript API based on an already existing spreadsheet

Is there a way to create an Add-in using Excel JavaScript API from an existing spreadsheet? When running npm start, it generates a blank workbook. I believe changes need to be made in the Manifest.xml file, as npm start triggers office-addin-debugging star ...

What is the best way to divide an array while extracting data from a JSON object using

Currently, I am parsing the json data. My goal is to find a specific property within the json object that contains two nested arrays (list and array). However, when extracting the values, they are all being stored in a single array. Is there a way to separ ...

I am trying to include the Css Baseline from @mui/material in my project. However, even though it is present in my JSON file, I am encountering an error stating that '@mui/material' needs to be included in the project

Struggling to import Css Baseline from @mui/material, it's listed in my json but I keep getting an error saying '@mui/material' should be included in the project's dependencies. I've been stuck on this issue for a while now! { &q ...

The React component does not trigger a re-render

Using React Redux, I am able to pass values successfully. However, the component I intend to render only does so once. Interestingly, when I save my code in VSCode, it renders again and the data displays on the page as expected. return ( <div classN ...

Locating specific text within an <li> element using the provided value

So, I have this set of words: <li>name</li> <li>myname</li> <li>yourname</li> Then there's also an input box input type="text" value="name" id="the_value" with the value "name", along with a submit button identif ...

Check the document's location if the page contains a class with a specific value

I am encountering an issue while using PHPMailer. I am trying to redirect the page after submitting a form and display a success popup window. After successfully submitting the form, a message is displayed in a popup window (JavaScript adds a class ' ...

Turn off error notifications from eslint parsing

Within my code, there is a conditional export that looks like this: if (process.env.NODE_ENV === 'testing') export myFunc; While in es6, this type of statement is typically not allowed due to the requirement for imports and exports to be top- ...

What is the best way to enable horizontal scrolling for textarea overflow in a smooth manner like input, without any sudden jumps?

Currently, I am interested in utilizing a one-line textarea (with rows=1 and overflow-x:hidden;) similar to input type="text. However, I have encountered an issue where the content scrolls with "jumps" while typing inside it: https://i.stack.imgur.com/Rzf ...

Is there a way to access and parse a CSV file from a URL within a Next.js project?

Currently working on a Next.js application available here. The task at hand requires reading a CSV file from a specific URL within the same repository in multiple instances. Unfortunately, I am encountering difficulties retrieving this data. You can locate ...

When velocity exceeds a certain threshold, collision detection may become unreliable

As I delve into detecting collisions between high-velocity balls, an obstacle arises. This issue seems to be quite common due to the nature of fast-moving objects colliding. I suspect that the solution lies within derivatives, and while I've drafted s ...

Detecting Unflushed Requests in Jasmine and AngularJS

I'm encountering some issues passing certain tests after implementing $httpBackend.verifyNoOustandingRequest(). Interestingly, excluding this from my afterEach function allows the tests to pass successfully. However, including it causes all tests to ...

Tips for integrating the C++ icon into a ReactJs project

For a ReactJs project, I needed to include icons of different Languages and Tools. When adding a Python icon, I used: <ListItem> <ListItemIcon className={classes.icon}> <span className="iconify" data-icon= ...

Using AngularJS forEach to assign properties to objects within a found set in ng-repeat

I am using an ng-repeat to display items from a JSON file, and they can be filtered based on user input. <tr ng-repeat="i in filteredItems = (iso3166 | filter: {alpha_2: isoQuery})"> Everything is working as expected. Each item in the "iso3166" gro ...

Update D3 data, calculate the quantity of rows in an HTML table, and add animations to SVGs in the final

Attempting to update data in an HTML table using D3 has proven to be quite challenging for me. My task involves changing the data in multiple columns, adjusting the number of rows, and animating SVG elements in each row based on new data arrays. Despite tr ...

JavaScript's asynchronous callbacks

As a PHP developer delving into the world of NodeJS, I find myself struggling to fully grasp the concept of asynchrony in JavaScript/Node. Consider this example with ExpressJS: router.get('/:id', function (req, res, next) { var id = req.par ...

Exploring the power of Vue.js with dynamic HTML elements and utilizing Vue directives within Sweet Alert

new Vue({ el: '#app', data(){ results: [] } }); I need assistance with implementing Vue directives, events, etc. within the markup of a Sweet Alert. The goal is to display an alert using Sweet Alert that include ...

What is the best way to display the value of a new object's property in Angular?

I am currently developing a list application that allows users to create new lists by entering a name and clicking a button. Once the list is created, users can add and remove items from the list. However, I have encountered an issue where the name of the ...

What can be done to stop the event handler from executing?

My goal is to verify a user's authentication every time they click on a button. If the user happens to be logged out and tries to click on a button, they should be redirected back to the home page. The issue I'm facing is that the code after the ...

Is it possible to trigger JavaScript after loading a page in jqTouch with AJAX?

Similar to the kitchensink demo, I have successfully used jqtouch to call external .html pages into the index page. One of these external pages contains a video that is being played using sublime player. Everything is pretty basic so far, but my challenge ...