When I try to upload a file using a post method, the req.file given by multer is returned undefined.
Maybe it's not getting the correct input by name? I'm really in the dark here.
Thank you in advance for your help
//Front-end form
<form action="/dashboard" method="POST" id="newproduct-form" class="row" enctype='multipart/form-data'>
<input type="file" name="productImage" class="form-control-file" id="exampleInputFile">
</form>
//Backend
const mongoose = require('mongoose');
const multer = require('multer');
const path = require('path');
//Set Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
//Init upload
const upload = multer({
storage: storage
}).single('productImage');
router.post('/dashboard', (req, res) => {
upload(req,res,(err) =>{
if(err) console.log(err);
console.log(req.file);
});
}
I figured it out. I was using jQuery ajax. By doing $(this).ajaxSubmit({ajax content}); instead of $.ajax({ajax content}) I managed to make it work.
Related
Preface: using Node.js w/Express to build a blog website and using multer to upload an image to mongoDB.
I have a problem with image data not saving to MongoDB.
When I use enctype="multipart/form-data in my HTML form, I get the following in my terminal
fieldname: 'myImage',
originalname: 'photo_2021-12-27_20-07-58.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './uploads/',
filename: 'photo_2021-12-27_20-07-58.jpg',
path: 'uploads\\photo_2021-12-27_20-07-58.jpg',
size: 134172
}
Which is correct, the image also uploads into a separate uploads folder which is also correct, however the image data doesn't save to my mongoDB.
However, when I remove enctype="multipart/form-data", I don't have the file data in my terminal, nor does the image upload to the separate folder. However I DO! get the image data in my mongoDB. This is such a weird problem. Can anyone help?
Also, sorry for the amount of code I have just unleashed. If anyone actually takes the time to answer this then thank you!
Routes
const express = require('express');
const router = express.Router();
const blogController = require('../controllers/blogController')
const multer = require('multer');
const storage = multer.diskStorage({
//destination for files
destination: function (request, file, callback) {
callback(null, './uploads/');
},
//add back the extension
filename: function (request, file, callback) {
callback(null, file.originalname);
},
});
const upload = multer({
storage: storage,
});
router.get('/create', blogController.blog_create_get);
router.get('/', blogController.blog_home);
router.post('/', upload.single('myImage') ,blogController.blog_create_post);
router.get('/:id', blogController.blog_details);
router.delete('/:id', blogController.blog_delete_post);
module.exports = router
Controller code
const blog_create_post = (req, res) => {
console.log(req.file);
const blog = new Blog(req.body, {
})
blog.save()
.then(() => {
res.redirect('/blogs')
})
.catch((err) => {
console.log(err);
})
}
Schema
image: {
data: Buffer,
contentType: String
},
const Blog = mongoose.model('Blog', blogSchema)
module.exports = Blog;
Midleware
// Static Files | Middleware
app.use(express.static('Public'));
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'))
app.use('/uploads',express.static('uploads'))
HTML form
<form action="/blogs" enctype="multipart/form-data" method="POST">
<label for="image">Select image:</label>
<input type="file" id="image" name="myImage" accept="image/*">
<input type="submit" value = "Upload Photo">
Multer is triggered only when the enctype of your form is enctype="multipart/form-data". Example from their doc:
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
When you don't provide this enctype your req object contains form data in text, and then it is saved to your database, of course.
In order to save binary data to MongoDB you need to open a file designated by
filename: 'photo_2021-12-27_20-07-58.jpg',
path: 'uploads\\photo_2021-12-27_20-07-58.jpg',
and save it appropriately (as text or binary depending on the format and reqs) to the mongodb. To read file check this answer
I wanted to upload images using nodeJS and multer, so I did the following:
Below is my multer configuration:
var multer = require('multer');
var storage = multer.diskStorage({
//Setting up destination and filename for uploads
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
var upload = multer({
storage: storage,
limits:{
fieldSize: 1024*1024*6,
}
});
Below is my route to upload image:
router.post('/designer', upload.single('designerImage'), async (req, res) => {
console.log(req.file);
//rest of the code which is not needed for my query
})
It works perfectly fine when I POST the file using form-data key of type file using POSTMAN. But when I try to send it using a HTML form input, req.file comes out to be undefined and no file gets uploaded to the uploads folder. Below is my HTML form code:
<form action="/designer" method="POST">
<input type="file" name="designerImage">
<form>
What is the solution to this problem? I've spend hours but couldn't get to a solution.
multer only parses multipart/form-data requests, so you need to add enctype="multipart/form-data" to your form
<form action="/designer" method="POST" enctype="multipart/form-data">
<input type="file" name="designerImage">
<form>
I'm trying to pass a file from my Angular app to a node.js server.
When I run the app, I get the following error:
Error: Please choose files
HTML:
<upload name="fileUpload" formControlName="fileUpload" #fileUpload (listChange)="updateList($event)" data-kind="primary"
[imagePreview]="true">
</upload>
Here is my updateList() method:
updateList(list: any) {
this.demolist = Array.apply(this, list);
this.attachmentReady.emit(this.demolist);
}
Node:
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const multer = require('multer');
let nodemailer = require('nodemailer');
let aws = require('aws-sdk');
const fs = require('fs');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
var upload = multer({ storage: storage });
app.post('/postData', upload.array('fileUpload', 12), (req, res, next) => {
console.log(req.body);
res.json(req.body);
const files = req.files
if (!files) {
const error = new Error('Please choose files')
error.httpStatusCode = 400
return next(error)
}
res.send(files);
}
In a different project, multer is working as expected. Below is the HTML from that project:
<form action="/uploadmultiple" enctype="multipart/form-data" method="POST">
Select images: <input type="file" name="myFiles" multiple>
<input type="submit" value="Upload your files" />
</form>
The difference between my working code & the code that isn't working is that I'm able to use a standard input control if the type is file.
But I need to use an upload control now & my code isn't working when I make that one change.
Can someone please tell me how I can use this control to pass the file? Thanks a lot in advance!
After you have installed multer using npm install --save multer
Basic usage example:
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/uploadmultiple', upload.single('myFiles'), function (req, res, next) {
// req.file is the `myFiles ` file
// req.body will hold the text fields, if there were any
})
app.post('/uploadmultiple', upload.array('myFiles', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
For more information you can read documentation here
I have a problem with my uploader. I think everything with code is right and still the file isnt created in uploads folder. Also when i try to console.log(req.files) i get an empty array. I try to make it locally
Here is the code:
const express = require("express"),
app = express(),
multer = require("multer"),
bodyParser=require("body-parser"),
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now() + '.' + mime.extension(file.mimetype));
}
});
var upload = multer({ storage : storage }).array('userPic');
app.post("/postFormAct", isLoggedIn, function(req, res){
upload(req,res,function(err) {
console.log(req.files);
});
});
Also there is my form:
<form method="post" action="/postFormAct" enctype="multipart/form-data">
<input type="text" name="user"><br>
<input type="text" name="email"><br>
<input type="file" name="userPic"><br>
<input type="submit" value="Submit">
</form>
I think you have an issue with your function level middleware, you have isLoggedIn, you have to chain the multer middleware upload right after like so :
// ...
var upload = multer({ storage : storage }).array('userPic');
app.post("/postFormAct", isLoggedIn, upload, function(req, res){
console.log(req.files)
});
Here's a full working example :
const app = require('express')()
const bodyParser = require('body-parser')
const multer = require('multer')
const morgan = require('morgan')
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({
storage: storage
})
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(morgan('dev'))
isLoggedIn = (req, res, next) => {
console.log('check if user is logged in')
next()
}
app.post('/uploads', isLoggedIn, upload.array('images'), (req, res) => {
console.log(req.files);
return res.send(req.files);
})
app.listen(8000, () => {
console.log(`server is listenning on port 8000`)
})
You can find a test repository here
Also make sure that your destination dir exist.
Instead of var upload = multer({ storage : storage }).array('userPic');
use
var upload = multer({ storage : storage }).any('userPic');
.any()
Accepts all files that comes over the wire. An array of files will be stored in req.files.
I just discovered something about Express middleware with multer.
You need to pass an array as middleware if you have more than one function that needs to act as middleware.
So this:
app.post('/uploads', isLoggedIn, upload.array('images'), (req, res) => {
console.log(req.files);
return res.send(req.files);
})
should become this:
app.post('/uploads', [upload.array('images'), isLoggedIn], (req, res) => {
console.log(req.files);
return res.send(req.files);
})
Note: Also notice that the upload middleware needs to go first...I don't know why this happens but that's the only way it worked for me.
I'm just putting this out there if anyone needs help with this(even though the question is pretty old and has an accepted answer).
I have a file upload in node js. I want to show a line displaying upload started / upload failed / upload completed and a graphic progress bar.
How can I implement this?
Node.js:
var express = require('express');
var router = express.Router();
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './upload');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).array('file', 3);
router.get('/', function(req, res){
res.send( {success: 'File uploaded!'});
})
router.post('/upload', function(req,res){
upload(req,res,function(err) {
console.log('Selected Files: ', req.files);
if(err){
res.end("Error: '" , err , "'");
}else{
console.log('Files uploaded!');
res.sendStatus(204);
}
});
});
module.exports = router;
HTML
<form enctype = "multipart/form-data"
action = "/upload"
method = "POST"
>
<input type="file" name="file"/>
<p></p>
<input type="file" name="file"/>
<p></p>
<input type="submit" value="Upload File" name="submit">
</form>
<p id="success">{{success}}</p>
Use XMLHttpRequest and .addEventListener("progress") on the client side to submit the form