The following code produces an image in the desired location, however, the image is not being named correctly.
routes.js
var upload = multer({
dest: './client/shared/assets/images/logos',
rename: function (fieldname, filename, req, res) {
console.log('Rename YO!')
console.log(fieldname)
console.log(filename)
console.log(req)
return 'test' + '-'+Date.now();
}
});
app.post('/uploads/logo',upload.single('file'), function(req, res){
console.log('Upload photo yo!')
console.log(req.body) // form fields
console.log(req.file) // form files
res.status(204).end()
});
create.controller.js
$scope.saveLogo = function(file) {
console.log(file);
file.upload = Upload.upload({
url: '/uploads/logo',
method: 'POST',
fields: {
name: $scope.item.name,
subdomain: $scope.item.subdomain
}
});
file.upload.then(function (_res) {
console.log(_res)
file.result = _res.data;
}, function (_res) {
console.log(_res)
if (_res.status > 0)
$scope.errorMsg = _res.status + ': ' + _res.data;
});
file.upload.progress(function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
};
I don't know what I am missing here. I am trying to limit the multer functionality to a specific post action, could that be it?
Thanks in advance
Solved with this little tidbit:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
The approach has changed to the above method since the last release
Related
I have a form with text-fields & drop-downs.
I am using Node.js , Angular js, Express, MongoDb.
I want to post data along with image(s).
I want to store image in folder, without any base/binary conversion, and image path should be stored in mongoDb.
How can I achieve this?
HTML FILE
<div class="form-group">
<label class="col-md-4">Profile Photo</label>
<input type="file" class="form-control"
formControlName="s_profile"
#s_profile ng2FileSelect
[uploader]="uploader"
(change)="uploader.uploadAll()" />
</div>
<div class="form-group">
<button (click)="addfile()"
[disabled]="angForm.pristine || angForm.invalid"
class="btn btn-primary">Upload</button>
</div>
COMPONENT FILE
const URL = 'http://localhost:4000/api/upload';
public uploader: FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});
ngOnInit() {
this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
//console.log('ImageUpload:uploaded:', item, status, response);
console.log(response);
this.profilPhotos = response;
};
}
addfile(){
this.ss.addStudent(this.profilPhotos);
}
SERVICE FILE
uri = 'http://localhost:4000/business';
addBusiness(uploadImages) {
const obj = {uploadImages: uploadImages};
this.http.post(`${this.uri}/add`, obj)
.subscribe(res => console.log('Done'));
}
SERVER FILE
const DIR = '../src/assets/upload';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
console.log(file);
cb(null, file.originalname);
}
});
let upload = multer({storage: storage});
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.post('/api/upload',upload.single('angular'), function (req, res) {
if (!req.file) {
console.log("No file received");
return res.send({
success: false
});
} else {
console.log('file received');
return res.send(req.file.filename)
}
});
ROUTER FILE
const path = require('path');
const fs = require('fs');
const express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser');
const app = express();
const router = express.Router();
const DIR = './uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + '.' + path.extname(file.originalname));
}
});
let upload = multer({storage: storage});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.post('/api/upload',upload.single('photo'), function (req, res) {
if (!req.file) {
return res.send({
success: false
});
} else {
return res.send({
return res.send(req.file.filename)
})
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, function () {
console.log('Node.js server is running on port ' + PORT);
});
You can use the simple/lightweight ng-file-upload directive. It supports drag&drop.
<div ng-controller="MyCtrl">
<input type="file" ngf-select="onFileSelect($files)" multiple>
</div>
JS:
angular.module('myApp', ['ngFileUpload']);
var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
$scope.onFileSelect = function($files) {
Upload.upload({
url: 'api/upload',
method: 'POST',
file: $files,
}).progress(function(e) {
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}];
You can use formidable for parsing form data, especially file uploads. Read more here
app.post('/api/upload', function(req, res) {
var form = new formidable.IncomingForm();
form.multiples = true;
form.uploadDir = path.join(__dirname, '../../public/images');
form.on('file', function(field, file) {
//copy file to new path
fs.renameSync(file.path, path.join(form.uploadDir, file.name));
var Image = path.join(form.uploadDir, file.name);
//save new path to mongodb
db.collection('images').insert({
imagePath: Image
}, function(err, result) {
// do your stuff
})
});
})
This is just my suggestion. You should learn more and do what you expect. Hope it help.
Front-End:
HTML:
<input type="file" nv-file-select uploader="vm.uploader"
id="fileUpload" ng-model="vm.schema.file"/>Browse
Controller:
angular
.module('myApp')
.controller('myController', myController);
myController.$inject = ['FileUploader'];
function EditSchemaBasicController(FileUploader) {
vm.uploader = new FileUploader({
url: "https://localhost:3000/api/file", //your api URL
queueLimit: 10,
onAfterAddingFile: function(item) {
//before upload logic will go here like file size and extension handling
item.upload();
},
onCompleteItem: function(item, response){
//on complete
console.log('Uploaded File: ' + response.file);
},
onErrorItem: function(item, response) {
//error handling
}
});
}
Back-End:
'use strict'
var express = require('express');
var router = express.Router();
var fs = require('fs-extra');
//Post file.. i used busboy to upload the file
router.post('/', function(req, res, next) {
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
filename = decodeURI(filename);
//Path where file will be uploaded
var fstream = fs.createWriteStream('API/Images' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.status(201).json({file: filename});
});
});
});
module.exports = router;
I am trying to upload my files with ng file upload but they are uploaded with some different file name on the server.I want them to get saved with the file name they have originally with their correct extension(.jpg,.pdf).
Below is my code.
Controller:
$scope.uploadPic = function (file) {
$scope.advert.userDetails={
"name":userDetails.name,
"email":userDetails.email,
"role":userDetails.role
}
file.upload = Upload.upload({
url: '/api/uploaders/uploads',
method: 'POST',
fields: {
details: $scope.advert
},
file: file,
fileFormDataName: 'photo'
});
file.upload.then(function (response) {
console.log("Postcontroller: upload then ");
$timeout(function () {
file.result = response.data;
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
});
file.upload.progress(function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
console.log("PostController: upload progress " + file.progress);
});
file.upload.success(function (data, status, headers, config) {
// file is uploaded successfully
console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);
console.log(data);
});
}
Api:
var multer = require('multer');
var upload = multer({ dest: 'server/uploads/images'});
It's not ng-upload changing the filename, it's multer. This is for security reasons.
In a nutshell, you wouldn't want someone to know the exact path of a file they've uploaded - what if it were malicious? They could potentially execute it.
If you really want, however, you can do this on your API side:
var multer = require('multer');
var storage = multer.diskStorage(
{
destination: 'server/uploads/images',
filename: function (req, file, cb) {
cb(null, file.originalname);
}
}
);
var upload = multer(storage);
I would like to send a file to my Node.js application, but it seems that the application receives nothing. I'm not sure what to do. How am I supposed to check If I have sent the file, and if I am receiving it in req?
<form>
<input type = "file" file-model="files" multiple/>
<button class="md-primary md-button md-cyan-theme md-ink-ripple" ng-click = "vm.uploadFile()">upload me</button>
</form>
This is my controller:
function uploadFile() {
console.log("Load");
var fd = new FormData();
console.log($scope.files) // FileList {0: File, Length: 1}
angular.forEach($scope.files, function (file) {
fd.append('file', file);
});
console.log(fd); // FormData {} (Empty?)
$http.post('http://localhost:8090/file-upload'), {
headers: {'Content-Type': undefined },
files: fd
}).success(function (d) {
console.log(d);
});
}
This is my directive:
.directive('fileMode', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('change', function () {
$parse(attrs.fileModel).assign(scope, elemtn[0].files);
scope.$apply();
});
}
};
}])
Here is my Express app:
app.post('/file-upload', function (req, res, next) {
console.log("Sent!");
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, file.fieldname);
}
});
var upload = multer({ storage : Storage }).array('userPhoto', 2);
upload(req, res, function (err) {
console.log(req.body.data.files);
if (err) return res.end("Error uploading file.");
res.end("File is uploaded.");
})
})
Thank you for the help.
The field names are not the same in web-form and in multer configuration:
var upload = multer({ storage : storage }).array('file',2);
Hope this will work!
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
multer = require('multer');
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost");
res.header(
"Access-Control-Allow-Origin",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.use(express.static('../client'));
app.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
var split = file.originalname.split('.');
cb(null, file.fieldname + "-" + Date.now() + "." + split[split.length - 1]);
}
});
var upload = multer({ storage : storage }).single('file');
app.post('/upload', function (req, res) {
upload(req, res, function (err) {
if (err) res.json({ error_code: 1, err_desc: err });
res.json({error_code: 0, err_desc: null });
})
})
app.listen('3000', function () {
console.log("Running on 3000");
})
If I use the example in multer's readme, I can upload a single file without problems. However, when I use the same sample I cannot do so for multiple files. I tried using the regular
Error: Unexpected field
at makeError (/Users/mroker/node_projects/JWT_Auth_Basic/node_modules/multer/lib/make-error.js:12:13)
at wrappedFileFilter (/Users/mroker/node_projects/JWT_Auth_Basic/node_modules/multer/index.js:39:19)
at Busboy. (/Users/mroker/node_projects/JWT_Auth_Basic/node_modules/multer/lib/make-middleware.js:112:7)
at emitMany (events.js:108:13)
at Busboy.emit (events.js:182:7)
HTML
<div class="button btn btn-danger" ngf-select ng-model="files" name="files" ngf-multiple="true">Select</div>
submit
APP.JS
if($scope.files){
console.log('upload multiple works');
console.log($scope.files);
$scope.uploadFiles($scope.files);
}
};
//FOR MULTIPLE FILES
$scope.uploadFiles = function (files) {
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
Upload.upload({
url: 'api/admin/photos',
data: {file: files[i]}
}).then(function(resp){
console.log('Successfully ' + resp.config.data.file.name);
$scope.myPic = resp.config.data.file.name;
},
function(resp){
console.log('Error status: ' + resp.status);
},
function(evt){
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
})
}
}
};
NODE JS
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/img')
},
filename: function (req, file, cb) {
//cb(null, file.originalname + '-' + Date.now())
cb(null, file.originalname )
}
});
var upload = multer({ storage: storage });
apiRoutes.post('/admin/photos',upload.array('files'),function(req,res){
//save to database
var photo = new Photos({
url: req.file.originalname,
name: req.file.filename
});
photo.save(function(err,docs){
if(err) throw err;
});
console.log(req.files);
console.log(req.file.originalname);
//console.log(req.file.originalname);
res.json(req.files);
});
Lastly when I use an error checking with app.use I get the following node error
{ [Error: Unexpected field]
code: 'LIMIT_UNEXPECTED_FILE',
field: 'file[0]',
storageErrors: [] }
If you upload multiple files and use upload.array('files') then your uploaded files are available in req.files, and this is an array of files.
edit: simple example how to change your code:
apiRoutes.post('/admin/photos',upload.array('files'),function(req,res){
req.files.forEach(function(file) {
//and here you have file.originalname and file.filename
});
});
edit1:
from APP.JS send files in one request:
//FOR MULTIPLE FILES
$scope.uploadFiles = function (files) {
Upload.upload({
url: 'api/admin/photos',
data: {file: files}
});
};
I had to change
data: {file: files}
to
data: {file: files[i}
this solved it.
Change your Upload script in angular
you should send separate object for image and your object name must match in both nodejs and angular js
Use following code
Upload.upload({
url: 'api/admin/photos',
data: somedata,
file_name: file_name
})
For multiple files
Upload.upload({
url: 'api/admin/photos',
data: somedata,
files: files
})
I am trying to upload multipart/form-data for a simple MEAN stack application. When putting everything in one file and running it it works fine.
Server.js
var express = require('express');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
switch(file.mimetype) {
case 'image/jpg' :
case 'image/jpeg':
case 'image/gif':
var extension = file.mimetype.split("/");
extension = extension[extension.length-1];
break
case 'video/quicktime':
var extension = 'mov';
break
case 'video/mp4':
var extension = 'mp4';
break
default:
var extension = 'jpeg';
}
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
});
var upload = multer({ storage: storage });
var path = require('path');
var app = express();
var segmentUpload = upload.fields([{ name: 'segmentVideo', maxCount: 1}, { name: 'segmentStill', maxCount: 1}, { name: 'segmentGif', maxCount: 1}])
app.post('/photos/upload', segmentUpload, function (req, res, next) {
console.log(req);
console.log(req.files['segmentVideo'][0]);
console.log(req.files['segmentStill'][0]);
console.log(req.files['segmentGif'][0]);
console.log(req.body.title);
});
app.get('/', function(req, res) {
res.sendfile('./index.html');
});
app.listen(8080);
console.log("App listening on port 8080");
index.html
<body>
<form action="/photos/upload" method="post" enctype="multipart/form-data">
title: <input type="text" name="title"> <br><br>
Select video to upload:
<input type="file" name="segmentVideo" id="fileToUpload"> <br><br>
Select jpeg to upload:
<input type="file" name="segmentStill" id="fileToUpload"><br><br>
Select gif to upload:
<input type="file" name="segmentGif" id="fileToUpload"><br><br>
<input type="submit" value="Upload Image" name="submit">
</form>
But when I try to integrate multer into my node routing I cannot get my app to accept the multipart/form-data.
app/routes.js
var Video = require('./models/video');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
switch(file.mimetype) {
case 'image/jpg' :
case 'image/jpeg':
case 'image/gif':
var extension = file.mimetype.split("/");
extension = extension[extension.length-1];
break
case 'video/quicktime':
var extension = 'mov';
break
case 'video/mp4':
var extension = 'mp4';
break
default:
var extension = 'jpeg';
}
console.log("new extension: " + extension);
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
});
var upload = multer({ storage: storage });
module.exports = function(app) {
// api --------------------------------------
// get all todos
app.get('/api/videos', function(req,res){
// use mongoose to get all todos in the database
Video.find(function(err, videos){
// if there is an error, send the error
if (err)
res.send(err);
res.json(videos);
});
});
var segmentUpload = upload.fields([{ name: 'segmentVideo', maxCount: 1}, { name: 'segmentStill', maxCount: 1}, { name: 'segmentGif', maxCount: 1}])
app.post('/api/videos', segmentUpload, function(req, res){
// create a video
Video.create({
title : req.body.title,
description : req.body.description,
category : req.body.category,
day : req.body.day,
videoUrl : req.body.videoUrl,
stillUrl : req.body.stillUrl,
gifUrl : req.body.gifUrl,
airReady : false
}, function(err, video) {
if (err)
res.send(err)
// get and return all the todos after you create another
Video.find(function(err, videos){
if (err)
res.send(err)
res.json(videos);
});
});
});
// delete a todo
app.delete('/api/videos/:video_id', function(req,res){
Video.remove({
_id : req.params.video_id
}, function(err, video) {
if (err)
res.send(err);
// get and return all the todos after you delete one
Video.find(function(err, videos) {
if (err)
res.send(err)
res.json(videos);
});
});
});
// edit a todo
app.put('/api/videos/:video_id', function(req,res){
Video.findByIdAndUpdate(req.params.video_id,
{ $set: { title: req.body.title
}},
function(err, video){
if (err)
res.send(err)
// get and return all todos after edit
Video.find(function(err, videos){
if (err)
res.send(err)
res.json(videos);
});
});
});
// find -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
};
I receive an error:
TypeError: Cannot read property 'title' of undefined
This is my first post to stack overflow, but I appreciate all of the support!
The problem might be due to use are sending the multipart/form-data but you are not converting it to json and you are using json for retrieving the data.
Use body-parser
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());