I have a full MERN stack project with Redux and AXIOS. I used FormData to upload the images to my node server which has the multer and it works perfectly fine on my localhost even tho console on my chrome said empty? (FormData {}). When it's deployed, my FormData is empty. So I tested my FormData without the files(just the input value from forms) and it passes to the server and has it on req.body.
I tried to add config my formData and didn't work.
What am i doing wrong???
For Example
config: { headers: { 'Content-Type': 'multipart/form-data' } }
etc.....
Here are some of my codes:
REACT Form JS
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import TextAreaFieldGroup from "../common/TextAreaFieldGroup";
import InputGroup from "../common/InputGroup";
import { addEventful, upload } from "../../actions/eventfulActions";
import Dropzone from "react-dropzone";
const imageMaxSize = 10000000
; //bytes
const acceptedFileTypes =
"image/x-png, image/png, image/jpg, image/jpeg, image/gif";
const acceptedFileTypesArray = acceptedFileTypes.split(",").map(item => {
return item.trim();
});
class EventfulForm extends Component {
constructor(props) {
super(props);
this.state = {
eventtitle: "",
description: "",
// comments:'',
files: [],
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentWillReceiveProps(newProps) {
if (newProps.errors) {
this.setState({ errors: newProps.errors });
}
}
verifyFile(files){
if(files && files.length > 0){
const currentFile = files[0]
const currentFileType = currentFile.type
const currentFileSize = currentFile.size
if(currentFileSize > imageMaxSize){
alert("TOO MANY FILES")
return false
}
if (!acceptedFileTypesArray.includes(currentFileType)) {
alert("IMAGES ONLY")
return false
}
return true
}
}
onSubmit(e) {
e.preventDefault();
const { user } = this.props.auth;
const formdata = new FormData();
this.state.files.forEach((file, i) => {
const newFile = { uri: file, type: "image/jpg" };
formdata.append("file", file, file.name);
});
// const newEventful = {
// eventtitle: this.state.eventtitle,
// description: this.state.description,
// pictures: this.state.pictures,
// name: user.name
// };
formdata.append("eventtitle", this.state.eventtitle);
formdata.append("description", this.state.description);
formdata.append("name", user.name);
this.props.addEventful(formdata);
this.setState({ eventtitle: "" });
this.setState({ description: "" });
this.setState({ files: [] });
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onDrop = (files, rejectedFiles) => {
if(rejectedFiles && rejectedFiles.length > 0){
console.log(rejectedFiles)
this.verifyFile(rejectedFiles)
}
if (files && files.length > 0) {
const isVerified = this.verifyFile(files)
if(isVerified){
console.log(files[0].name);
const formdata = new FormData();
files.map(file => {
formdata.append("file", file, file.name);
});
// formdata.append("file", files[0], files[0].name);
console.log(formdata);
// this.props.upload(formdata);
this.setState({
files: files
});
}
}
};
render() {
const previewStyle = {
display: "inline",
width: 100,
height: 100
};
const { errors, files } = this.state;
return (
<div className="post-form mb-3">
<div className="card card-info">
<div className="card-header bg-info text-white">Create an Event</div>
<div className="card-body">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<InputGroup
placeholder="Create a event title"
name="eventtitle"
value={this.state.eventtitle}
onChange={this.onChange}
error={errors.eventtitle}
/>
{files.length > 0 && (
<Fragment>
<h3>Files name</h3>
{files.map((picture, i) => (
<p key={i}>{picture.name}</p>
))}
</Fragment>
)}
<Dropzone
onDrop={this.onDrop.bind(this)}
accept={acceptedFileTypes}
maxSize={imageMaxSize}
>
<div>
drop images here, or click to select images to upload.
</div>
</Dropzone>
<TextAreaFieldGroup
placeholder="Description"
name="description"
value={this.state.description}
onChange={this.onChange}
error={errors.description}
/>
</div>
<button type="submit" className="btn btn-dark">
Submit
</button>
</form>
</div>
</div>
</div>
);
}
}
EventfulForm.propTypes = {
addEventful: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors,
eventful: state.files
});
export default connect(
mapStateToProps,
{ addEventful, upload }
)(EventfulForm);
My FormAction.js
import axios from "axios";
import {
ADD_EVENTFUL,
GET_ERRORS,
ADD_LIKE,
REMOVE_LIKE,
GET_EVENTFUL,
GET_EVENTFULS,
DELETE_EVENTFUL,
CLEAR_ERRORS,
EVENTFUL_LOADING,
UPLOAD_FILES
} from "./types";
const config = {
onUploadProgress: progressEvent =>
console.log(
"Upload Progress" +
Math.round((progressEvent.loaded / progressEvent.total) * 100) +
"%"
)
};
// Add eventful
export const addEventful = eventfulData => dispatch => {
dispatch(clearErrors());
// .post("/api/eventfuls", eventfulData, config)
axios({
method: 'post',
url: '/api/eventfuls',
data: eventfulData,
config: { headers: { 'Content-Type': 'multipart/form-data' } }
}).then(res =>
dispatch({
type: ADD_EVENTFUL,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
node.js
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const passport = require("passport");
const bodyParser = require("body-parser");
// Eventful model
const Eventful = require("../../models/Eventful");
const User = require("../../models/User");
// Validation
const validateEventfulInput = require("../../validation/eventful");
const validateCommentInput = require("../../validation/comment");
var multer = require("multer");
var fs = require("fs");
var path = require("path");
var btoa = require("btoa");
router.use(
bodyParser.urlencoded({
extended: false
})
);
router.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, __dirname + "../../../uploads"); //you tell where to upload the files,
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
}
});
var upload = multer({
storage: storage
}).array("file");
router.use((request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header(
"Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
response.header("Access-Control-Allow-Headers", "Content-Type");
next();
});
// @route POST api/eventfuls
// @desc Create eventful
// @access Private
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
upload(req, res, err => {
console.log("req.body!!!!!", req.body);
const { errors, isValid } = validateEventfulInput(req.body);
// Check Validation
if (!isValid) {
console.log(errors);
// If any errors, send 400 with errors object
return res.status(400).json(errors);
}
console.log("req.files!!!!!", req.files);
if (err) {
console.log(err);
res.status(404).json({
uploadFailed: "Upload failed"
});
} else {
let newArr = [];
for (let file of req.files) {
let fileReadSync = fs.readFileSync(file.path);
let item = {};
item.image = {};
item.image.data = fileReadSync;
item.image.contentType = "img/png";
newArr.push(item);
fs.unlink(file.path, function(err) {
if (err) {
console.log("error deleting image", file.path);
} else {
console.log("deleted image", file.path);
}
});
}
for (var i = 0; i < newArr.length; i++) {
var base64 = btoa(
new Uint8Array(newArr[i].image.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
newArr[i].image.data = base64;
}
console.log("33333333333333333333", newArr);
const newEventful = new Eventful({
title: req.body.eventtitle,
description: req.body.description,
pictures: newArr,
user: req.user.id,
name: req.user.name
});
newEventful.save().then(eventful => res.json(eventful));
}
console.log("skipped....................");
}
);
}
);
ERRORS/ LOGS on my PM2
0|server | 2019-01-13 21:27 -07:00: Server is ready to take messages 0|server | 2019-01-13 21:28 -07:00: req.body!!!!! [Object: null prototype] {} 0|server | 2019-01-13 21:28 -07:00: req.files!!!!! [] 0|server | 2019-01-13 21:28 -07:00: { [Error: ENOENT: no such file or directory, open '/var/www/LCTW/uploads/file-1547440111023'] 0|server | 2019-01-13 21:28 -07:00: errno: -2, 0|server | 2019-01-13 21:28 -07:00: code: 'ENOENT', 0|server | 2019-01-13 21:28 -07:00: syscall: 'open', 0|server | 2019-01-13 21:28 -07:00: path: '/var/www/LCTW/uploads/file-1547440111023', 0|server | 2019-01-13 21:28 -07:00: storageErrors: [] }
on here my req.body and req.files are empty. BUT
when I commented out files parts out on my node.js, req.body exist!
0|server | 2019-01-13 21:40 -07:00: req.body!!!!! [Object: null prototype] {
0|server | 2019-01-13 21:40 -07:00: eventtitle: 'asdfas',
0|server | 2019-01-13 21:40 -07:00: description: 'asdfads',
0|server | 2019-01-13 21:40 -07:00: name: 'In Soo Yang' }