react js handling file upload - javascript

I'm new to react js. I want to upload image asynchronously with react js
Suppose I have this code
var FormBox = React.createClass({
getInitialState: function () {
return {
photo: []
}
},
pressButton: function () {
var data = new FormData();
data.append("photo", this.state.photo);
// is this the correct way to get file data?
},
getPhoto: function (e) {
this.setState({
photo: e.target.files[0]
})
},
render: function () {
return (
<form action='.' enctype="multipart/form-data">
<input type='file' onChange={this.getPhoto}/>
<button onClick={this.pressButton}> Get it </button>
</form>
)
}
})
ReactDOM.render(<FormBox />, document.getElementById('root'))
Any answer will be appreciated!

You can make use of FileReader
var FormBox = React.createClass({
getInitialState: function () {
return {
file: '',
imagePreviewUrl: ''
}
},
pressButton: function () {
e.preventDefault();
// TODO: do something with -> this.state.file
console.log('handle uploading-', this.state.file);
},
getPhoto: function (e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(file);
},
render: function () {
let {imagePreviewUrl} = this.state;
let imagePreview = null;
if (imagePreviewUrl) {
imagePreview = (<img src={imagePreviewUrl} />);
} else {
imagePreview = (<div className="previewText">Please select an Image for Preview</div>);
}
return (
<div>
<form action='.' enctype="multipart/form-data">
<input type='file' onChange={this.getPhoto}/>
<button onClick={this.pressButton}> Get it </button>
</form>
<div className="imgPreview">
{imagePreview}
</div>
</div>
)
}
})
ReactDOM.render(<FormBox />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="root"></div>

If you are planning to upload files using node and express then you have to create both server and client. The server has the api and the client is going to use that for uploading the file with axios.
Server part
First, we want to put in four packages that are express, explicit-fileupload,cors and nodemon. Run the below command to install applications.
npm i express express-fileupload cors nodemon
Now open the fileupload folder in your favorite code editor and create a brand new document referred to as server.js.
// server.js
const express = require('express');
const fileUpload = require('express-fileupload');
const cors = require('cors')
const app = express();
// middle ware
app.use(express.static('public')); //to access the files in public folder
app.use(cors()); // it enables all cors requests
app.use(fileUpload());
// file upload api
app.post('/upload', (req, res) => {
if (!req.files) {
return res.status(500).send({ msg: "file is not found" })
}
// accessing the file
const myFile = req.files.file;
// mv() method places the file inside public directory
myFile.mv(`${__dirname}/public/${myFile.name}`, function (err) {
if (err) {
console.log(err)
return res.status(500).send({ msg: "Error occured" });
}
// returing the response with file path and name
return res.send({name: myFile.name, path: `/${myFile.name}`});
});
})
app.listen(4500, () => {
console.log('server is running at port 4500');
})
use node server.js to start the server running.
Client
Open the react app folder on your favorite code editor and create a brand new report known as fileupload.js within the src folder. Now upload the following code.
// fileupload.js
import React, { useRef, useState } from 'react';
import axios from 'axios';
function FileUpload() {
const [file, setFile] = useState(''); // storing the uploaded file
// storing the recived file from backend
const [data, getFile] = useState({ name: "", path: "" });
const [progress, setProgess] = useState(0); // progess bar
const el = useRef(); // accesing input element
const handleChange = (e) => {
setProgess(0)
const file = e.target.files[0]; // accesing file
console.log(file);
setFile(file); // storing file
}
const uploadFile = () => {
const formData = new FormData();
formData.append('file', file); // appending file
axios.post('http://localhost:4500/upload', formData, {
onUploadProgress: (ProgressEvent) => {
let progress = Math.round(
ProgressEvent.loaded / ProgressEvent.total * 100) + '%';
setProgess(progress);
}
}).then(res => {
console.log(res);
getFile({ name: res.data.name,
path: 'http://localhost:4500' + res.data.path
})
}).catch(err => console.log(err))}
return (
<div>
<div className="file-upload">
<input type="file" ref={el} onChange={handleChange} />
<div className="progessBar" style={{ width: progress }}>
{progress}
</div>
<button onClick={uploadFile} className="upbutton">
Upload
</button>
<hr />
{/* displaying received video*/}
{data.path && <video src={data.path} autoPlay controls />}
</div>
</div>
);
}
export default FileUpload;
Now import the FileUpload component inside the App.js file.
// App.js
import React from 'react';
import FileUpload from './fileupload';
import './App.css';
function App() {
return (
<div className="App">
<FileUpload />
</div >
);
}
export default App;
Start the react app by running npm start.
For more: React File Upload Demo

import axios from 'axios';
var FormBox = React.createClass({
getInitialState: function () {
return {
photo: [],
name : '',
documents:[]
}
},
pressButton: function () {
var component = this
var data = new FormData();
data.append("photo", component.state.photo, component.state.name);
var request = axios.post('http://localhost:3000/document', data)
request.then(function(response){
// you need to send data from server in response
if(response.status == 200){
console.log('saved in db')
component.state.documents.push(response.data.documents)
// pushed document data in documents array
}
})
},
getPhoto: function () {
var uploadfile = document.getElementById(upload_doc).files[0]
this.setState({
photo: uploadfile, name : uploadfile.name
})
},
render: function () {
var documents = this.state.documents.map((doc)=>{
return <div>
<a href={doc.url}>{doc.name}</a>
<img src={doc.photo} />
</div>
})
// you can show your documents uploaded this way using map function
return (
<form action='.' enctype="multipart/form-data">
<input type='file' id='upload_doc' onChange={this.getPhoto}/>
<button onClick={this.pressButton}> Get it </button>
<span>{documents}</span>
// this way you can see uploaded documents
</form>
)
}
})
ReactDOM.render(<FormBox />, document.getElementById('root'))

One more easier way, by using using axios node module axios-fileupload
npm install --save axios-fileupload
const axiosFileupload = require('axios-fileupload');
axiosFileupload(url,file);

You can use React Dropzone Uploader, which gives you a dropzone that shows file previews (including image thumbnails) for dropped or chosen files, and also handles uploads for you.
import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'
const Uploader = () => {
return (
<Dropzone
getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
accept="image/*,audio/*,video/*"
/>
)
}
Uploads have progress indicators, and they can be cancelled or restarted. The UI is totally customizable, and the library has no dependencies.
Full disclosure: I wrote this library.

Use following module to select images.
https://www.npmjs.com/package/react-image-uploader
You can then upload image to server using xhr request. Following is the sample code.
var xhr = new XMLHttpRequest();
xhr.onload = function (e) {
//your success code goes here
}
var formData = new FormData();
xhr.open("POST", url, true);
formData.append('file', fileData);
xhr.send(formData);

You can use whatwg-fetch to make a post request. In your pressButton() function make the following changes -
import 'whatwg-fetch';
//....
pressButton: function (url) {
var data = new FormData();
data.append("photo", this.state.photo);
var options = {
body: data,
timeout: 3000 * 60 * 60
};
let callOptions = {
method : 'POST',
headers : {
'Content-Type': 'application/json'
},
body : JSON.stringify(options.body)
}
return fetch(url, callOptions).then(response => response.json());
}

Retrieve all the data in the form by using FormData then get all the inputs value and create a post request using axios with header 'content-type': 'multipart/form-data', that's how it works.
const CreateProfile = () => {
const handleFormSubmit = async (event) => {
event.preventDefault();
const form = new FormData(event.currentTarget);
const data = {
name: form.get('name'),
email: form.get('email'),
phone: form.get('phone'),
image: form.get('image'),
}
const response = await axios.post('https://example.com/api/create/profile',data,{ headers: {
'content-type': 'multipart/form-data'
}});
console.log(response);
}
return (
<div>
<form onSubmit={(event) => handleFormSubmit(event)} method="post">
<input type="text" name="name" required />
<input type="email" name="email" required />
<input type="tel" name="phone" required />
<input type="file" accept="image/jpg, image/png, image/webp" name="image" required />
<button type="submit">Submit</button>
</form>
</div>);
}

Related

PDF along with text not getting uploaded to Express from React

I want to send book details along with the pdf of the book to the database.
This is a portion of my react code.
const {user}=useSelector((state)=>state.auth)
const [file, setFile] = useState(null);
const dispatch = useDispatch()
const { values, errors, touched, handleBlur, handleChange, handleSubmit, setFieldValue } = useFormik({
initialValues: initialValues,
validationSchema: addBookSchema,
onSubmit: async(values, { resetForm }) => {
// i have used FormData only to send pdf
const formData = new FormData()
formData.append('title', values.title)
formData.append('author', values.author)
formData.append('rating', values.rating)
formData.append('numOfRatings', values.numOfRatings)
formData.append('total', values.total)
formData.append('genre', values.genre)
formData.append('file', file)
const response = await axios.post('http://localhost:5000/api/admin', formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${user.token}`,
},
});
console.log(response.data);
resetForm()
}
})
return (
// some code
<Box>
<TextField
id="pdf-input"
// label="Upload PDF"
type="file"
accept=".pdf"
// className={classes.textField}
onChange={handleFileChange}
margin="normal"
/>
</Box>
// some code
Below is my express controller which handles this input from react
// this is to start connection
const url = process.env.MONGO_URI;
const connect = mongoose.createConnection(url, { useNewUrlParser: true, useUnifiedTopology: true });
let gfs;
connect.once('open', () => {
// initialize stream
gfs = new mongoose.mongo.GridFSBucket(connect.db, {
bucketName: "uploads"
});
});
// this is the controller
const addBook = asyncHandler(upload.single('file'),async (req, res) => {
console.log(req.file.file);
console.log(req.body);
// nothing gets logged in console
res.status(200).json(req.body)
});
below is my upload middleware used in my controller
const path = require("path");
const multer = require("multer");
const { GridFsStorage } = require("multer-gridfs-storage");
const crypto = require("crypto");
const storage = new GridFsStorage({
url: process.env.MONGO_URI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "uploads",
};
resolve(fileInfo);
});
});
},
});
const upload = multer({ storage });
module.exports = upload;
i get the following errors
//1. if i do formData.append('file', file) then i get "Warning: An unhandled error was caught from submitForm()"
//2. if i do formData.append('ebook', file) then i get "message: 'Unexpected field', stack: 'MulterError: Unexpected field\n"
//3. Nothing gets logged in my console when i console.log(req.body) in my controller.
Note: I am able to successfully send data to my database if i do not use FormData and do not take file input.
I tried various methods but i could not identify the problem. Any helps is very much appreciated. Thanks in advance.

React-js: How to upload Image with preview and display the processe image

Looking for some help in creating a React-js component to upload an image with preview and display the returned processed Image. API server return a binary png and not a url to the image. Resulting image should be displayed in a separate Div
Regards
I am not able to find a good example to upload image to a API server and display the returned binary image file
Use this code as a sample:
const MyComponent = () => {
const [previewImage, setPreviewImage] = useState(null);
const [uploadedImage, setUploadedImage] = useState(null);
const handleUploadImage = () => {
const data = new FormData();
data.append('files[]', previewImage);
fetch(/* server url */, { method: 'POST', body: data }).then(async (response) => {
const imageResponse = await response.json();
setUploadedImage(imageResponse);
}).catch((err) => {
});
}
const handleSelectImage = (event) => {
const file = event.target.files[0];
const fileReader = new FileReader();
fileReader.addEventListener("load", () => {
setPreviewImage(fileReader.result);
});
fileReader.readAsDataURL(file);
}
return (
<div>
<input type="file" onChange={handleSelectImage} />
{
previewImage ?
<img src={previewImage} alt="preview-image" />
:
null
}
{
uploadedImage ?
<img src={uploadedImage} alt="uploaded-image" />
:
null
}
<button onClick={handleUploadImage}>Upload</button>
</div>
);
}

Upload multiple files using formidable and vue js

Hey guys i am trying to make an app in which i neeed to upload multiple files
but in my node backend when i try to upload files using postman it works
but while using with vue js it does not work
this is my node backend where i use formidable and try to upload images
app.post('/multiple', (req, res) => {
var form = new formidable.IncomingForm(),
files = [],
fields = [];
form.on('field', function (field, value) {
console.log('fields is', field);
fields.push([field, value]);
});
form.on('file', function (field, file) {
console.log('i came inside file');
console.log(file.name);
const oldPath = file.path;
const newPath = path.join(__dirname, 'uploads/' + file.name);
const rawData = fs.readFileSync(oldPath);
console.log('old path', oldPath);
fs.writeFileSync(newPath, rawData);
console.log('file uploaded');
console.log(JSON.stringify(field));
files.push([field, file]);
});
form.on('end', function () {
console.log('done');
});
form.parse(req);
console.log(files);
return res.json(files);
});
and this is my vue js front end component code
this is html code for vue js
<template>
<div>
<button #click="items++">Add One More File</button>
<form #submit.prevent="handleImageUpload">
<div v-for="item in items" :key="item">
<input type="file" #change="handleFile($event, item)" />
</div>
<input type="submit" />
</form>
</div>
</template>
and this is script tag for component
<script>
import axios from 'axios';
export default {
data() {
return {
items: 1,
files: [],
};
},
methods: {
async handleImageUpload() {
try {
const fd = new FormData();
this.files.map((index, file) => {
fd.append(index, file);
});
const { data } = await axios.post('http://localhost:5000/multiple', fd);
console.log('data from backend is ', data);
} catch (error) {
console.log(error);
}
},
handleFile(e, item) {
console.log(e);
this.files[item - 1] = e.target.files[0];
},
},
};
</script>
now what happend when I request backend with form data everything goes undefined there
ok so it was my mistake , I was writing map function the wrong way
it should be
this.files.map((file,index) => {

How to update files using Axios and React

I've built an api with posts/articles, and now I'm working on the front end. I'm having an issue with uploading a new photo for an already existing post. I've attempted the two most common methods for the photo, formData and JSON Base64. I'm receiving the same error response for both methods, Please upload a file, code: 400. I'm not certain where I've gone wrong, so I'll provide every relevant file.
articles.js(server)
exports.articlePhotoUpload = asyncHandler(async (req, res, next) => {
const article = await Article.findById(req.params.id);
if (!article) {
return next(
new ErrorResponse(`Article not found with id of ${ req.params.id }`, 404)
);
}
//Make sure user is article owner || make sure user is admin
if (article.user.toString() !== req.user.id || req.user.role !== 'admin') {
return next(
new ErrorResponse(
`User ${ req.user.id } is not authorized to update this article`,
)
)
}
if (!req.files) {
return next(new ErrorResponse(`Please upload a file`, 400))
}
const file = req.files.file;
// Confirm the image is a photo
if (!file.mimetype.startsWith('image')) {
return next(new ErrorResponse(`Please upload an image file`, 400))
}
// Check File Size
if (file.size > process.env.MAX_FILE_UPLOAD) {
return next(
new ErrorResponse(`Please upload an image less than ${ MAX_FILE_UPLOAD }`, 400)
)
}
// Create custom filename
file.name = `photo_${ article._id }${ path.parse(file.name).ext }`;
file.mv(`${ process.env.FILE_UPLOAD_PATH }/${ file.name }`, async err => {
if (err) {
console.log(err);
new ErrorResponse(`Problem with file upload`, 500);
}
await Article.findByIdAndUpdate(req.params.id, { photo: file.name });
res.status(200).json({
success: true,
data: file.name
});
});
});
^the above function is where the error message is triggered server-side.
axios.js(client-side)
...
axios.defaults.baseURL = 'http://<<ip address>>/api/v1';
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('auth');
axios.defaults.headers.post['Content-Type'] = 'application/json';
export const uploadPhoto = (id, data) => {
return axios.put(`/articles/${ id }/photo`, {
data
})
}
...
^I have a feeling I could format this exported function better. I might be missing something here.
UploadPhoto.jsx(JSON Attempt)
const UploadPhoto = (props) => {
const { register, handleSubmit } = useForm();
const { state } = useStateMachine(updateAction);
const [file, setFile] = useState(null);
const [filename, setFilename] = useState(null);
const onSubmit = async () => {
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
console.log(reader.result)
});
const data = {
title: filename,
file: await toBase64(file),
}
uploadPhoto(`5ea5e73044718d0b2c2ae5df`, data)
.then(res => console.log(res))
.catch(err => console.log(err.response.data.error))
}
const handleChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h2>Cover Image</h2>
<label>
Select A File:
</label>
<img id="image" src="" alt="" />
<input
type="file"
name="photo"
ref={register}
defaultValue={state.data.photo}
onChange={handleChange}
/>
<label htmlFor="">
Filename
</label>
<input type="submit" />
</form>
)
}
export default withRouter(UploadPhoto);
UploadPhoto.jsx(formData attempt)
const onSubmit = () => {
const formData = new FormData();
formData.append("file", file);
console.log(file)
uploadPhoto(`5ea5e73044718d0b2c2ae5df`, formData)
.then(res => console.log(res))
.catch(err => console.log(err.response.data.error))
}
This is my first time building my own api, which is why I put the server code in here. However, I'm 90% sure I'm making a mistake client-side, most likely in the axios.js file.
Let's try this example:
const fileUpload = require('express-fileupload');
const app = express();
// enable files upload -- this should also make 'req.files' accessible
app.use(fileUpload({
createParentPath: true
}));
Add this in the beginning of your server initialization. After that your normal code should try accessing req.files as it should be filled on file upload requests now.
You will need to install module express-fileupload before using it in code -> npm i express-fileupload
(Source: https://attacomsian.com/blog/uploading-files-nodejs-express)

can't upload a image to express api with Multer from react

I want to upload a image from my react app to my express API.
i made something like this in vainla js and it work ed with same endpoint but in react project doesn't work .
I created a react component like this:
import React, { useState } from "react";
import BackupIcon from "#material-ui/icons/Backup";
import url from "../url";
import Preview from "./Preview";
const AdaugaImg = props => {
const [file, setFile] = useState(null);
const [ales, setAles] = useState(false);
const [imgUrl, setImgUrl] = useState("");
const modificare = e => {
//console.log(e.target.value);
setFile(e.target.files[0]);
setAles(true);
const urlImg = URL.createObjectURL(e.target.files[0]);
//console.log(urlImg);
//reader.onloadend = e => setImgUrl(reader.result);
setImgUrl(urlImg);
};
const upload = async e => {
e.preventDefault();
setAles(false);
console.log("incarcare");
console.log(file);
try {
const data = new FormData();
data.append("img", file);
const res = await fetch(`${url}/add`, {
method: "POST",
data: data
});
console.log(await res.json());
} catch (error) {
console.log(error);
}
};
const closePreview = () => setAles(false);
const preview = ales ? (
<Preview imgUrl={imgUrl} closePreview={closePreview} />
) : null;
return (
<div className="upload">
{preview}
<form method="POST" onSubmit={upload}>
<input
type="file"
name="img"
id="poza"
style={{ width: 0.1, height: 0.1 }}
onChange={modificare}
/>
{!ales ? (
<label for="poza" className="upload-label">
<p>Selecteaza o poza</p>
</label>
) : null}
<button className="upload-btn" type="submit">
<BackupIcon />
<p>Incarca poza</p>
</button>
</form>
</div>
);
};
export default AdaugaImg;
them I wrote code. for api using multer
const router = require("express").Router();
const multer = require("multer");
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "img-biserici/");
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "_" + Date.now() + "_.jpg");
}
});
const upload = multer({
storage: storage
});
router.post("/add", upload.array("img", 1), (req, res) => {
console.log(req.files[0]);
res.json({ ok: true });
});
when I upload image in console it shows me this error:TypeError: Cannot read property '0' of undefined .what I missed?and how to fix this?
You are missing content type in headers.
const res = await fetch(`${url}/add`, {
method: "POST",
data: data,
headers: {
'Content-Type': 'multipart/form-data'
}
});

Categories