How to pass a file data in JSON payload to restful API - reactjs

How can we pass file data along with other key-value pairs in the JSON payload in ReactJs?
I have a form where one input is of file type and others are simple text type input boxes. I have to pass the file and other input values to the restful post API in the JSON format from the frontend.

Could you provide a bit more context for this question?
A shot in the dark is you could use:
const ImportFromFileBodyComponent = () => {
let fileReader;
const handleFileRead = (e) => {
const content = fileReader.result;
console.log(content)
// … do something with the 'content' …
};
const handleFileChosen = (file) => {
fileReader = new FileReader();
fileReader.onloadend = handleFileRead;
fileReader.readAsText(file);
};
return <div className='upload-expense'>
<input
type='file'
id='file'
className='input-file'
accept='.csv'
onChange={e => handleFileChosen(e.target.files[0])}
/>
</div>;
};
This might provide you the contents of the file and you can use those in the application you desire.

Related

Attempting to send uploaded file in React app to backend returning 'undefined'

I'm currently building some functionality in my React web app to upload a picture, display it on the client (this works), but also store the photo details so they can be sent in an axios post to my backend where the image gets stored in the file system.
Here's my code to now:
const SetupDetails = () => {
const [previewPhoto, setPreviewPhoto] = useState(null)
const [photoFile, setPhotoFile] = useState(null)
const uploadPhoto = (e) => {
e.preventDefault()
setPreviewPhoto(URL.createObjectURL(e.target.files[0]))
setPhotoFile(e.target.files[0])
}
const buttonClick = (e) => {
e.preventDefault()
console.log(previewPhoto)
console.log(photoFile)
axios.post("/api/uploadProfilePicture", {
photoFile: photoFile
})
}
const deletePhoto = (e) => {
e.preventDefault()
setPreviewPhoto(null)
setPhotoFile(null)
}
return (
<label for="photo-upload" className="setup-photo-label">Upload</label>
<input className="setup-photo-input" id="photo-upload" type="file" onChange={uploadPhoto} />
{
previewPhoto ?
<div className="preview-photo-container">
<img className="preview-photo" src={previewPhoto} alt="A small thumbnail uploaded by the user." />
<button className="preview-photo-delete" onClick={deletePhoto}>Delete</button>
</div> : null
}
<button className="setup-continue-button" onClick={buttonClick}>Continue</button>
)
}
The basic premise is:
The input calls a function during 'onChange' which updates state to store the details of the photo
The 'photoFile' details are posted to the backend to be stored in the backend
The 'previewPhoto' is used to display a thumbnail of the image to the user
However, the photoFile is returned as undefined, or an empty object, every time.
I'm not 100% sure where I'm going wrong, as the console.log of the 'photoFile' shows the details of the photo, so I'd have thought I could just post that to the backend.
Any advice here would be really appreciated!

ReactJS-Leaflet: upload csv file in leaflet

here I have a question regarding references to creating a feature in the react leaflet.
So, the feature has the following functions =
The user page when they want to upload a location is in the form of a csv file containing latitude and longitude.
When the user clicks the red button above, a popup will appear to upload the csv file.
When finished uploading the csv file, it will go directly to the location based on latitude and longitude.
So my question is, does anyone have a tutorial on how to create a csv upload button that points directly to a map with reactjs and leaflets? Thank you very much
Although you have not asked to use react-leaflet I would advise you to do so because you will end up in a mess when you will have to export the map reference to reuse it across places.
First create a button that will handle the upload of a csv file. There is a really useful guide to do so without the use of libraries like paparse although it simplifies a lot this procedure. Next you need to transform the csv columns to some form of data to use. This is also included in the guide. You end up with an array of csv columns.
Then all you need to do is to create a custom react-leaflet component to render the markers and zoom to the markers viewport.
Also you can clean the csv file once you insert a new one.
function App() {
const [csvToArray, setCsvToArray] = useState([]);
const fileReader = new FileReader();
const csvFileToArray = (string) => {
const csvHeader = string.slice(0, string.indexOf("\n")).split(",");
const csvRows = string.slice(string.indexOf("\n") + 1).split("\n");
const array = csvRows.map((i) => {
const values = i.split(",");
const obj = csvHeader.reduce((object, header, index) => {
object[header] = values[index];
return object;
}, {});
return obj;
});
setCsvToArray(array);
};
const handleOnChange = (e) => {
if (csvFileToArray.length > 0) setCsvToArray([]);
const file = e.target.files[0];
if (file) {
fileReader.onload = function (event) {
const text = event.target.result;
csvFileToArray(text);
};
fileReader.readAsText(file);
}
};
console.log(csvToArray);
return (
<>
<input
type="file"
id="csvFileInput"
accept=".csv"
onChange={handleOnChange}
/>
<Map csvToArray={csvToArray} />
</>
);
}
function RenderCsvToArray({ csvToArray }) {
const map = useMap();
useEffect(() => {
if (csvToArray.length === 0) return;
const myPoints = csvToArray.map(({ Latitude, Longitude }) => [
Latitude,
Longitude
]);
const myBounds = new L.LatLngBounds(myPoints);
map.fitBounds(myBounds);
}, [csvToArray]);
return csvToArray?.map(({ Latitude, Longitude, Title }, index) => (
<Marker key={index} icon={icon} position={[Latitude, Longitude]}>
<Popup>{Title}</Popup>
</Marker>
));
}
You can see the full implementation on the demo
I have also inlcuded two csv files to play with in the form of
Title,Latitude,Longitude
Trinity College,41.745167,-72.69263
Wesleyan University,41.55709,-72.65691
and
Group,Title,Image,Description,Address,Latitude,Longitude
a,Trinity College,https://www.edx.org/sites/default/files/trinity1.jpg,"Not in the link view website more not in the link","300 Summit St - Hartford CT 06106,41.745167,-72.69263
a,Wesleyan University,https://upload.wikimedia.org/wikipedia/commons/4/41/You_are_here_-_T-shirt.jpg,"view website",45 Wyllys Ave Middletown CT 06459,41.55709,-72.65691

Reading multiple files using FileRead() and adding them on React State

So I'm building an app that allows you to chose more than one photo, on chose I set the files in React State then i listed for change for that state with useEffect so I can iterate and convert to base64 using FileRead to preview what I've uploaded. But I'm having a problem that the data I'm getting is weird, some of the files are read and added to the React State and some just appear just as File, here is the screenshot:
Here is the screenshot of the Console Log (can't add the object because is to long)
And here is how I add to the state the files on upload:
<input
className={styles.hidden_input}
type='file'
multiple='multiple'
accept='image/*'
onChange={(event) => {
const files = event.target.files;
if (files) setImages(files);
else setImages(null);
}}
And here is how I convert them when uploads are made:
useEffect(() => {
if (images.length !== 0) {
for (let i = 0; i < images.length; i++) {
let file = images[i];
const reader = new FileReader();
reader.onload = () => {
const single = reader.result;
setImagesStream([...images, single]);
};
reader.readAsDataURL(file);
}
} else {
console.log('No images where found.');
}
}, [images]);
When I try to iterate, just the last image shows the other show blank, because aren't converted.
You need to pass a function to the setState of 'setImagesStream' so it can read from the current value in the updater instead of reading the current value rendered. Here is the docs reference
Something like this should work:
setImagesStream((state) => {
return [...state, single]
});

React app - upload and read JSON file into variable without a server?

I'm building a JSON editor in React and right now I'm just fetching a json file from a static folder on the server and sticking it in a variable. I'd like to be able to use a file input and select any json file and read it into the variable.
Is this possible without a server?
That said, I also tried using an Express/Cors server but it's a bit outside my wheelhouse and I'm not sure how to install / run it on the production domain where this editor will live.
Have an input of type file and maintain a state and update the state upon onChange
working demo is here
Code snippet
import React, { useState } from "react";
export function Upload({ children }) {
const [files, setFiles] = useState("");
const handleChange = e => {
const fileReader = new FileReader();
fileReader.readAsText(e.target.files[0], "UTF-8");
fileReader.onload = e => {
console.log("e.target.result", e.target.result);
setFiles(e.target.result);
};
};
return (
<>
<h1>Upload Json file - Example</h1>
<input type="file" onChange={handleChange} />
<br />
{"uploaded file content -- " + files}
</>
);
}

Uploading multiple images in React

I would like to upload multiple images to send them off.
I tried this two ways in handleChange but the formdata is always empty.
I also want to know how to display the image in the react
state = { files: []}
fileChangeHandler = (e) => {
this.setState({ files: e.target.files })
this.setState({ files: [...this.state.files, ...e.target.files] })}
handleSubmit(event) {let fileData = new FormData();
fileData.append('files', this.state.files);
uploadClaimFile(response.data.id, fileData);}
the input
<input type="file" multiple onChange={this.fileChangeHandler} />
The safest way to append to a state array without directly modifying it is to make a shallow copy of the array, add the new items, and then replace the array using setState:
fileChangeHandler = (e) => {
const files = [...this.state.files]; // Spread syntax creates a shallow copy
files.push(...e.target.files); // Spread again to push each selected file individually
this.setState({ files });
}
As for uploading the files, when appending to a FormData object you must append the files one at a time:
handleSubmit(event) {
const fileData = new FormData();
this.state.files.forEach((file) => fileData.append('files[]', file));
// ... Submit fileData
}
Note: The use of [] in naming the data is in accordance with PHP naming conventions when uploading multiple files.
Edit
To answer your last question about displaying multiple uploaded files, you would want to write a method to take those files, create URLs that tie them back to the document, and display them. However, created URLs must be revoked to prevent memory leaks. Thus, it might be a good idea to store them in state to keep track of them, so you can implement it like this:
this.state = { files: [], urls: [] };
setFileUrls(files) {
const urls = files.map((file) => URL.createObjectURL(file));
if(this.state.urls.length > 0) {
this.state.urls.forEach((url) => URL.revokeObjectURL(url));
}
this.setState({ urls });
}
displayUploadedFiles(urls) {
return urls.map((url, i) => <img key={i} src={url}/>);
}
Call setFileUrls in your onChange handler, and call displayUploadedFiles in the render method:
render() {
return (
// ... other stuff
{this.state.urls.length > 0 &&
<Fragment>{this.displayUploadedFiles(this.state.urls)}</Fragment>
}
// ... more stuff
);
}
Multiple adjacent elements should be wrapped in a parent element, which can be a div or a React Fragment.
You can explore this npm module React Drop Zone.

Resources