This is similar to question: Excel to JSON javascript code?, but using React and Dropzone.
I either need to upload the Excel file to the server and parse it there, or parse it in the browser to JSON, then upload the JSON.
I have written React (frontend) and Server side (backend) to process a CSV file and store to MongoDB. The React side is below.
My two issues have been:
If I do it on the client side, how to use XSLX or sheetjs to read and process a file dropped using DropZone
If I do it on the server, how to properly upload the Excel file (I've read posts about setting Mime-Extension for Office/Excel). I've been able to upload a file, but I can never open it in Excel after it has been uploaded. It's usually double the size, probably UTF-8 to UTF-16 conversion happening.
import React, {useCallback, useState} from 'react';
import {useDropzone} from 'react-dropzone' // use hooks
import Dropzone from 'react-dropzone'
import XLSX from 'xlsx'
//import logo1 from './logo.svg'; // original
import logo2 from './images/ShedMadeOfWood_small.jpg'; // demo logo
import './App.css';
function App() {
// Edit <code>src/App.js</code> and save to reload.
// const [files, setFiles] = useState([])
const currDateTime1 = new Date().toISOString()
console.warn(currDateTime1 + " Starting React/App: function App()")
const onDrop = useCallback(acceptedFiles => {
// Do something with the files
const currDateTime2 = new Date().toISOString()
console.log(currDateTime2 + " trying to read file")
acceptedFiles.forEach((file) => {
const reader = new FileReader()
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onload = (data) => {
// Do what you want with the file contents
//console.log("file size:", data.length);
//const binaryStr = reader.result
//const fileContents = reader.readAsText
const fileContents = data.target.result
const currDateTime3 = new Date().toISOString()
console.log(currDateTime3 + " Text print of file contents:")
// console.log(fileContents)
// This fetch worked for CSV file
fetch('http://localhost:3001/api/filedata', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
// TODO - could add userid, datetime here, filename, etc...
body: JSON.stringify({
"fileContents": fileContents
//, secondParam: 'yourOtherValue',
})
})
// another example passed formData to the body: https://stackoverflow.com/questions/41025078/react-dropzone-how-to-upload-image
/*
fetch('http://localhost:3001/api/filedatabinary', {
method: 'POST',
body: fileContents
})
*/
}
reader.readAsText(file)
//reader.readAsBinaryString(file)
})
}, [])
const {getRootProps, getInputProps, isDragActive} = useDropzone ({onDrop})
const [fileNames, setFileNames] = useState([]);
const handleDrop = acceptedFiles =>
setFileNames(acceptedFiles.map(file => file.name));
return (
<div align="center">
<div className="App" {...getRootProps()}>
<header className="App-header">
<img src={logo2} className="App-logo" alt="logo" />
</header>
<h4>CSV Files here</h4>
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the files here ...</p> :
<div>
<p>Drag and Drop a csv file here,<br />
or click to select files.</p>
</div>
}
</div>
<h4>Drop Excel Files Here</h4>
<Dropzone onDrop={handleDrop}>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<p>Drag and drop Excel files, or click to select files</p>
</div>
)}
</Dropzone>
<div>
<strong>Excel File(s):</strong>
<ul>
{fileNames.map(fileName => (
<li key={fileName}>{fileName}</li>
))}
</ul>
</div>
<hr />
<br /><br />
Thanks for using our company!
</div>
);
}
export default App;
My server side code splits and loops through the rows of a CSV and saves them to MongoDB as JSON. I upload the contents of the CSV file as a single value of a JSON variable, then parse it on the server. My most recent change was to add two drop zones, one for CSV and one for Excel, using two different techniques. I can use two different REST methods on the server, one for the CSV and one for the binary, if needed. Or I can convert to JSON on the client, and just have one REST method on the server.