Reputation: 611
I've read through all the possible answers here but I'm not sure anymore what the problem could be because none of them works. I have one form that uploads a single image and it works as expected but on a different form where I try and upload multiple files and have form inputs, the req.file is always undefined and the image data ends up in the req.body. So somewhere I think maybe there is an issue where multer is not getting the file data...?
I read in a couple of places that body-parser is possibly not playing well with multer but I unfortunately need them both.
route
const destination = './public/uploads/posts';
const storage = multer.diskStorage({
destination: destination,
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
const upload = multer({storage}).array('images');
router.post('/posts', (req, res) => {
upload(req, res, (err) => {
if(err) {
console.log('errors', err)
res.json({success: false, error: err})
} else {
if(req.files === undefined) {
console.log('error: Images returned undefined');
} else {
const { title, description, url, auth_name, auth_id } = req.body;
if(!title || !description) {
return res.json({
success: false,
error: 'All fields required',
message: 'Title and description fields are required'
});
}
// path we store in the db
let imageLocation = [];
const post = new Post();
for (const file of req.files) {
imageLocation.concat('/uploads/posts/' + file.filename)
}
post.title = title;
post.description = description;
post.url = url;
post.author_name = auth_name;
post.author = auth_id;
post.images = imageLocation;
post.save((err, post) => {
if(err) {
return res.json({ success: false, error: err, message: 'post failed' });
} else {
return res.json({ success: true, message: "added new post", post: post });
}
});
}
}
});
});
post in react component
My images are set in state which I get from the DropZone package (I tested without DropZone as well with same results. I made sure the the input name is "images"
submitNewPost = () => {
const { title, description, url, images } = this.state;
const auth_id = this.props.author_id;
const auth_name = this.props.author_name;
const formdata = new FormData();
formdata.append('title', title);
formdata.append('description', description);
formdata.append('url', url);
formdata.append('author_name', auth_name);
formdata.append('author', auth_id);
formdata.append('images', images);
fetch('/api/posts', {
method: 'POST',
body: formdata
}).then(res => res.json())
.then((res) => {
if (!res.success) {
this.setState({ message: res.message });
} else {
this.setState({
title: '',
description: '',
url: '',
images: '',
message: res.message
});
socket.emit('newPost', res.post);
}
});
}
UPDATE
With some help on this thread I managed to upload the images using my existing route and postman. When I test the route using my form, I still get an empty req.file and no uploads.
I added express-multipart-file-parser to my setup and I figure that is what brought me one step closer to fixing this.
Server
This is what I added to my server.js
import { fileParser } from 'express-multipart-file-parser';
app.use(fileParser({
rawBodyOptions: {
limit: '15mb', //file size limit
},
busboyOptions: {
limits: {
fields: 20 //Number text fields allowed
}
},
}));
Upvotes: 0
Views: 2292
Reputation: 19
for this issue not getting req.file
in controller after upload middleware, while testing in postman select multiple file in single property and of course in front end append the files in a loop
doc.forEach(file=> {
formdata.append('file', file);
}
Upvotes: 0
Reputation: 611
thanks for all the help. I managed to fix it. Turns out I was concatenating the FileList object to an array in my state so the structure was all wrong and at the server it just failed. My images upload perfectly now.
If I posted that part of my react component, I'm sure any of you would have picked up on that in a second, sorry. Did not occur to me that the problem was further up in my component.
THE PROBLEM
onFileLoad = (e) => {
this.setState({
images: this.state.images.concat(e.target.files)
});
}
THE FIX
onFileLoad = (e) => {
this.setState({
images: e.target.files
});
}
submitMediaPOst = () => {
const imageArr = Array.from(images);
imageArr.forEach(image => {
formdata.append('images', image);
});
...
Upvotes: 3
Reputation: 715
You are missing to pass value with array.
router.post('posts', upload.array('image', 10), function (req, res, next) {
})
Upvotes: 0
Reputation: 6086
To properly populate req.files
you need to use formdata.append
like this:
images.forEach(image => {
formdata.append('images', image);
})
Upvotes: 5