I am using multer to upload form data( some image files).
But req.body and req.files both are coming empty. when I am uploading images I got the successful message " your image has been uploaded" but my folder is empty.
I tried all solution available on StackOverflow as well as GitHub.
but no luck.
below my code
form in the HTML file
<form id="uploadForm" enctype="multipart/form-data" action="multerFile" method="post">
<input type="file" name="userPhoto" multiple />
<input type="submit" value="Upload Image" name="submit">
<input type='text' id='random' name='random'>
<br>
<span id="status"></span>
</form>
<script>
$(document).ready(function () {
$('#uploadForm').submit(function () {
$("#status").empty().text("File is uploading...");
$(this).ajaxSubmit({
error: function (xhr) {
status('Error: ' + xhr.status);
},
success: function (response) {
console.log(response)
$("#status").empty().text(response);
}
});
return false;
});
});
</script>
index.js
app.post('/multerFile', function (req, res) {
console.log("hi i am multer function")
var storage = multer.diskStorage({
destination: 'C:/Users/chandra/Documents/project/node_project/public'
});
var upload = multer({ storage: storage }).array('userPhoto', 2);
upload(req, res, function (err) {
if (err) {
console.log(err);
return res.end("Error uploading file.");
} else {
console.log(req.body)
console.log(req.files);
req.files.forEach(function (f) {
console.log(f);
// and move file to final destination...
});
res.end("File has been uploaded");
}
});
});
I tried:
Express, Multer, BodyParser req.body empty array
multer req.body showing empty always
https://github.com/expressjs/multer/issues/351
https://github.com/expressjs/multer/issues/391
and I followed this tutorial for multer
https://codeforgeek.com/2016/01/multiple-file-upload-node-js/
I am unable to understand that what am I doing wrong?
please help.
Thanks in advance
First, .ajaxSubmit() is not core jQuery functions. You need the jQuery Form Plugin and I don't know if you import it like below:
<script src="http://malsup.github.com/jquery.form.js"></script>
The easiest way to do it will be to do it without a plugin like this:
$('#uploadForm').submit(function() {
$("#status").empty().text("File is uploading...");
var formData = new FormData($('#uploadForm')[0]);
$.ajax({
type: 'POST',
url: '/multerFile',
data: formData,
success: function(response) {
console.log(response)
$("#status").empty().text(response);
},
contentType: false, // Prevent jQuery to set the content type
processData: false // Prevent jQuery to process the data
});
return false;
});
Now in your backend, your destination should better be (with a folder uploads in your public folder):
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
});
I just changed my storage to
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
And it is workings fine..
Related
I've been trying to upload an image for a while now, but req.file is still undefined. Can someone see why?
this is my page. I am able to pick an image when I click the '+' glyphicon, but on the server side req.file is still empty.
EJS file
input[type="file"] and input[type="submit"] have css styles display: none
<form action="/profile/addProfilepicture" method="post" id="form" enctype="multipart/form-data">
<span id="upload" class="glyphicon glyphicon-plus-sign"></span>
<label for="profilePic"></label>
<input id=profilePic type='file' />
<input type="submit">
</form>
<img class="profileImg"
src="<%="images/pexels-photo-370799.jpeg"%>"
alt="fail">
Client JS file
When I click the '+'glyphicon it lets me pick an image. When I do this, this will trigger the form to submit and send a post request.
$("#upload").on('click',function() {
$("input[type='file']").click();
});
$('input[type="file"]').change(function (e) {
$("input[type='submit']").click()
});
server side JS
On the server side it stops at:
TypeError: Cannot read property 'filename' of undefined
at C:\Users\Tijl Declerck\Desktop\projects\digitalNomadApp\routes\profile.js:27:38
at Immediate._onImmediate (C:\Users\Tijl Declerck\Desktop\projects\digitalNomadApp\node_modules\multer\lib\make-middleware.js:53:37)
at runCallback (timers.js:793:20)
at tryOnImmediate (timers.js:751:5)
at processImmediate [as _immediateCallback] (timers.js:722:5)
The console.logs I tried gave me this: req.body returns an empty object and req.file returns undefined.
var express = require('express');
var router = express.Router();
var multer = require('multer');
var User = require('../models/Users');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/profilePics')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
var upload = multer({ storage: storage }).single('myImage');
router.post('/addProfilePicture', function (req, res) {
var profilePicUrl = '';
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
} else {
console.log(req.file);
profilePicUrl = req.file.filename;
User.update({username: req.user.username}, {'profilePic.uploaded': true, 'profilePic.link': profilePicUrl}, function(err, doc){
console.log('THIS IS DONE')
});
}
});
});
You have to provide a name to your file input and it should match the single method's name, this is from multer doc:
.single(fieldname)
Accept a single file with the name fieldname. The single file will be
stored in req.file.
This is not well documented but fieldname refers to input name attribute
EJS file
<input id='profilePic' name='myImage' type='file' />
Express
...
var upload = multer({ storage: storage }).single('myImage');
...
So, I want to upload a picture and show it right below the page so it looks like I am "posting" the picture.
So here's what I did in NODEJS:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/img');
},
filename: function (req, file, cb){
cb(null, file.originalname);
}
});
var upload = multer({storage: storage});
app.post('/', upload.single('file'), function(req, res){
res.send(req.file);
});
So right now every time I upload a picture it goes right into the folder called 'img'.
Now I want to retrieve this img using ajax and that's what I did in JAVASCRIPT:
$("input[type=submit]").click(function(){
$.ajax({
type: 'POST',
url: '/',
success: function(data){
console.log(data);
}
});
});
However, I don't get anything from the success function in ajax, rather, I just go to another page where I can see this json:
{
fieldname: "file",
originalname: "extensao.jpg",
encoding: "7bit",
mimetype: "image/jpeg",
destination: "./public/img",
filename: "extensao.jpg",
path: "public/img/extensao.jpg",
size: 411576
}
How can I make this work and receive this JSON in my success function? I thought by doing res.send(req.file) I was already sending the data to my ajax request.
after you've saved the images, you can get them by using this piece of code. This will send the file to the user. Let's say you have a file named jeff.jpg inside ./public/img all you have to is to go to yourlink.com/files/jeff.jpg to retrieve it.
app.get('/files/:filename', function(req, res){
res.sendFile(__dirname + 'public/img/' + req.params.filename);
})
This means that you can also render the images in your html by only using img tag. For example,
<img src="./public/img/jeff.jpg"/>
This is the whole code to my main.js file,
var express = require('express')
var multer = require('multer')
var app = express();
var whereFilesAreStored = '/public/img';
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, __dirname + whereFilesAreStored) //you tell where to upload the files,
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
var upload = multer({storage: storage,
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
});
app.set('view engine', 'ejs');
app.get('/', function(req, res, next){
res.render('mult'); //our html document
})
app.get('/files/:filename', function(req, res){
res.sendFile(__dirname + whereFilesAreStored + '/' + req.params.filename);
})
//file upload
app.post('/post', upload.single('file'), function (req, res, next) {
console.log(req.file);
return false;
})
app.get('/ajax', function(req, res){
res.render('ajax');
})
To use the images in the client side, I have made a file named ajax as you can see above. this is my html.
Using ajax at this point is useless, it is only used to check if there's any updates on a page. But still I have made a small code for ajax for you to see. Don't use ajax for this task. you can use <img src="thelink"/> to get the file to your page. Please check my img tag down below.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Anasayfa</title>
<link type="text/css" rel="stylesheet" href="/cssDosyalari/ana.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
</head>
<body>
<script type="text/javascript">
var theUrl = 'http://localhost:2222/files/';
var fileName = "jeff.jpg";
var wholePath = theUrl + fileName;
$.ajax({
type: 'GET',
url: wholePath + fileName,
success: function(data){
console.log(data);
}
});
</script>
<img src="http://localhost:2222/files/jeff.jpg" alt="">
</body>
</html>
UPDATE
I have had problems with using ajax to it. Some reason, the link redirects me, so I have came up with this solution. I send the ajax, the server uploads the file, then makes the client reload the page with the image coming out. I am using ejs + ajax in here. Please check the code down below.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
</head>
<body>
<script type="text/javascript">
$('#my-form').submit( function(e) {
e.preventDefault();
//function myFunc(){
$.ajax({
url: '/post',
data: $('#myFile'),
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
}
})
e.preventDefault();
console.log('ajax sent');
return false;
// }
}
//onclick="myFunc()"
</script>
<form id="my-form" action="/post" method="post" enctype="multipart/form-data">
<input id="myFile" type="file" name="afile" value="">
<input type="submit" name="" value="submit">
</form>
<img id="theImgSrc" alt="">
<script type="text/javascript">
$( document ).ready(function() {
$('#theImgSrc').attr('src', 'http://localhost:2222/files/<%=fileName%>').load();
});
</script>
</body>
</html>
This is my main.js file,
app.get('/files/:filename', function(req, res){
res.sendFile(__dirname + whereFilesAreStored + '/' + req.params.filename);
})
app.get('/', function(req, res, next){
res.render('mult', {fileName: ''}); //our html document
})
app.post('/post', upload.single('afile'), function (req, res, next) {
res.render('mult', {fileName: req.file.originalname});
console.log(req.file);
})
I an trying to create a service which takes a xlsx template file and response a populated xlsx file with some values. What I have done so far is,
index.html
<input name="file" type="file" onchange="callthis()"/>
script.js
// callthis sends the file from client to server
function callthis() {
var formData = new FormData($(this).files[0]);
$.ajax({
url: '/uploadTemplate',
type: 'POST',
data: formData,
success: function (data) {
console.log(data);
alert(data)
},
cache: false,
contentType: false,
processData: false
});
}
serverRouter.js
router.post('/uploadTemplate', function(req, res, next){
let uploadedFilePath = null;
// I'm using multer for handling formdata in the server
var upload = multer({ dest: Locator.temp.temp });
//configure the multer
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, Locator.temp.temp);
},
filename: function (req, file, callback) {
uploadedFilePath = file.fieldname + '-' + Date.now() + '.xlsx';
callback(null, uploadedFilePath);
}
});
var upload = multer({ storage : storage}).single('file');
//in here i am uploading the file.
//and reading the file ugin XLSX modules.
//doing some changes to xlsx json object
//and write the data to a file in a temp folder
//i'm using res.download method to send downloadable file back to client
res.download(Path.join(Locator.temp.temp, uploadedFilePath));
});
})
Using above codes, i could upload the file and get response. success method prints out details i added with some unreadable characters. But i could not download the file.
How can i download the file. Are there any different and better approach for this situation.
You can't attach a download to an AJAX request. You will have to send the download URL in the AJAX response and then have your client side script open the URL
In the server:
let response = {downloadUrl: Path.join(Locator.temp.temp, uploadedFilePath)}
res.json(response)
In the client:
window.open(ajaxResponse.downloadUrl);
I am a NodeJS beginner, following along a book "Web Development with MongoDB and NodeJS". I am stuck at its chapter 6 with 'multer'. When I use multer for file uploads the server throws the following error:
/Users/fk / Documents / imageuploader / node_modules / express / lib / application.js: 209
throw new TypeError('app.use() requires middleware functions'); ^
TypeError: app.use() requires middleware functions
but when I replace it with bodyParser the server fires up but when I click the upload button it gives me the following error on the browser.
500 TypeError: Cannot read property 'file' of undefined
However, it is supposed to redirect me towards another page, where the uploaded file is shown.
Here is my bodyParser code, please see if I am using it correctly because it gives me "body-parser deprecated" at the starting of the server. I've seen other questions like mine and I followed but none of them really work.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser({
uploadDir: path.join(__dirname, '../public/upload/temp')
}));
Following code shows how I use multer, just in case if there is something I shouldn't be doing please let me know. Which one would be better in case of uploading files, body-parser or multer?
app.use(multer({
dest: path.join(__dirname, '../public/upload/temp')
}));
var saveImage = function() {
var possible = 'abcdefghijklmnopqrstuvwxyz0123456789',
imgUrl = '';
for (var i = 0; i < 6; i += 1) {
imgUrl += possible.charAt(Math.floor(Math.random() * possible.length));
}
var tempPath = req.files.file.path,
ext = path.extname(req.files.file.name).toLowerCase(),
targetPath = path.resolve('./public/upload/' + imgUrl + ext);
if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif') {
fs.rename(tempPath, targetPath, function(err) {
if (err) throw err;
res.redirect('/images/' + imgUrl);
});
} else {
fs.unlink(tempPath, function() {
if (err) throw err;
res.json(500, {
error: 'Only image files are allowed.'
});
});
}
};
saveImage();
Preceding block of code is the logic that I am using to upload the file. In the error it is referring to 'file' as undefined which is in the following line in the saveImage function. It is unable to get the path and therefore throws error 500 according to the else part of the saveImage function. Why is 'file' undefined here? I dont get it.
var tempPath = req.files.file.path,
multer() returns a middleware generator that uses the settings you specified, so you cannot pass its return value directly to app.use(). You can see all of the types of middleware it can generate in the documentation, but typically the generated middleware are added at the route level instead of globally like the other body parsers. This is because you will typically pass in the name of the file field(s) that you will be expecting.
For example, this will accept a single file (along with any non-file fields) whose form field name is foo:
var upload = multer({
dest: path.join(__dirname, '../public/upload/temp')
});
// ...
app.post('/upload', upload.single('foo'), function(req, res) {
if (req.file) {
console.dir(req.file);
return res.end('Thank you for the file');
}
res.end('Missing file');
});
Also, body-parser does not currently export a multipart/form-data-capable middleware, so you cannot use that module for handling uploaded files (well, short of passing a base64-encoded string in an application/x-www-form-urlencoded form or something, but that's much less efficient).
Here is the basic code for file upload in MEAN please check
HTML
<form id="frmDoc" name="frmDocument" ng-submit="upload()" class="form-horizontal form-bordered" enctype="multipart/form-data" >
<fieldset>
<div class="form-group">
<label class="col-md-4 control-label" for="val_email">Document<span class="text-danger">*</span></label>
<div class="col-md-4">
<div class="input-group">
<input type="file" name="file" id='file' required="required" />
</div>
</div>
</div>
</fieldset>
<div class="form-group form-actions">
<div class="col-md-8 col-md-offset-4">
<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-upload"></i> submit</button>
</div>
</div>
</form>
CLIENT SIDE CODE
app.controller ('myctrl',function($scope,$http){
$scope.upload = function () {
var file = angular.element(document.querySelector('#file')).prop("files")[0];
$scope.files = [];
$scope.files.push(file);
$http({
method: 'POST',
url: '/users/upload',
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append('model', angular.toJson(data.model));
formData.append('file', data.files[0]);
return formData;
},
data: { model: { title: 'hello'}, files: $scope.files }
}).success(function (res) {
console.log(res)
});
}
});
SERVER SIDE CODE
var multer = require('multer');
var mkdirp = require('mkdirp');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
//var code = JSON.parse(req.body.model).empCode;
var dest = 'public/uploads/';
mkdirp(dest, function (err) {
if (err) cb(err, dest);
else cb(null, dest);
});
},
filename: function (req, file, cb) {
cb(null, Date.now()+'-'+file.originalname);
}
});
var upload = multer({ storage: storage });
router.post('/upload', upload.any(), function(req , res){
console.log(req.body);
res.send(req.files);
});
I corrected the code of the book "Web Development with MongoDB and NodeJS" as follows:
app.use(multer({dest:path.join(__dirname,'../public/upload/temp')}).any());
.
.
.
.
const tempPath = req.files[0].path, // Temporary location of uploaded file
ext = path.extname(req.files[0].originalname).toLowerCase(), // Get file extension of the uploaded file
targetPath = path.resolve(`./public/upload/${imgUrl}${ ext}`); // The final path for the image file
The other parts of code remained intact. It worked and I could upload image files.
Best wishes,
Mehrdad Sheikhan
Code for upload file using Multer and save it to local folder
api- call fileUpload function
fileUpload(req)
.then(uploadRes => {
console.log('uploadRes', uploadRes)
})
.catch(err => {
console.log('err', err)
})
Create file upload service
const multer = require('multer') // import library
const moment = require('moment')
const q = require('q')
const _ = require('underscore')
const fs = require('fs')
let dir = './public'
/** Store file on local folder */
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, dir)
},
filename: function (req, file, cb) {
let date = moment(moment.now()).format('YYYYMMDDHHMMSS')
cb(null, date + '_' + file.originalname.replace(/-/g, '_').replace(/ /g, '_'))
}
})
/** Upload files */
let upload = multer({ storage: storage }).array('files')
/** Exports fileUpload function */
module.exports = {
fileUpload: function (req) {
let deferred = q.defer()
/** Create dir if not exist */
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
console.log(`\n\n ${dir} dose not exist, hence created \n\n`)
}
upload(req, {}, function (err) {
if (req && (_.isEmpty(req.files))) {
deferred.resolve({ status: 200, message: 'File not attached', data: [] })
} else {
if (err) {
deferred.reject({ status: 400, message: 'error', data: err })
} else {
deferred.resolve({
status: 200,
message: 'File attached',
filename: _.pluck(req.files,
'filename'),
data: req.files
})
}
}
})
return deferred.promise
}
}
I am trying to upload image to nodejs server using ajax but it fails to get file.
Client Side
function sendFileToServer(file){
var formData = new FormData();
formData.append('profile_image',file,file.name);
$.ajax({
type: "POST",
url: "URL",
data: formData,
dataType:'json',
processData: false,
success: function (data) {
alert("Data Uploaded: "+data);
},
error : function(err){
alert(JSON.stringify(err));
}
});
}
$("#profile_image_2").change(function(){
var file = this.files[0];
sendFileToServer(file);
});
Server Side
var multer = require('multer');
var mime = require('mime-lib');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/upload/')
},
filename: function (req, file, cb) {
console.log("filename exte "+file.mimetype);
console.log(mime.extension(file.mimetype));
cb(null, Date.now() + '.' + mime.extension(file.mimetype)[0]);
//crypto.pseudoRandomBytes(16, function (err, raw) {
// cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
//});
}
});
var uploading = multer({ storage: storage });
router.post('/profile',uploading.single('profile_image') ,function(req,res){
if (req.file){
res.json("In here");
}else{
res.json("FILE DOES NOT EXIST");//ALWAYS ENDS UP HERE
}
});
When i try it in bare form it works fine, but not using ajax. Please help
Try to use jQuery Form Plugin. It will make this for you.