Uploading multiple files with Multer - javascript

I'm trying to upload multiple images using Multer. It all works as expected except that only one file is being uploaded (the last file selected).
HTML
<form class='new-project' action='/projects' method='POST' enctype="multipart/form-data">
<label for='file'>Select your image:</label>
<input type='file' multiple='multiple' accept='image/*' name='uploadedImages' id='file' />
<span class='hint'>Supported files: jpg, jpeg, png.</span>
<button type='submit'>upload</button>
</form>
JS
//Define where project photos will be stored
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, './public/uploads');
},
filename: function (request, file, callback) {
console.log(file);
callback(null, file.originalname)
}
});
// Function to upload project images
var upload = multer({storage: storage}).any('uploadedImages');
// add new photos to the DB
app.post('/projects', function(req, res){
upload(req, res, function(err){
if(err){
console.log(err);
return;
}
console.log(req.files);
res.end('Your files uploaded.');
console.log('Yep yep!');
});
});
I get the feeling I'm missing something obvious...
EDIT
Code I tried following Syed's help:
HTML
<label for='file'>Select your image:</label>
<input type='file' accept='image/*' name='uploadedImages' multiple/>
<span class='hint'>Supported files: jpg, jpeg, png.</span>
<input type="submit" value="uploading_img">
JS
multer = require('multer'),
var upload = multer();
app.post('/projects', upload.array('uploadedImages', 10), function(req, res, err) {
if (err) {
console.log('error');
console.log(err);
}
var file = req.files;
res.end();
console.log(req.files);
});

Uploading multiple files with Multer
NodeJs Code
Set require files and Storage
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const port = 3000
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, './images/'))
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + file.originalname.match(/\..*$/)[0])
}
});
Set upload file limit or validataion
const multi_upload = multer({
storage,
limits: { fileSize: 1 * 1024 * 1024 }, // 1MB
fileFilter: (req, file, cb) => {
if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "image/jpeg") {
cb(null, true);
} else {
cb(null, false);
const err = new Error('Only .png, .jpg and .jpeg format allowed!')
err.name = 'ExtensionError'
return cb(err);
}
},
}).array('uploadedImages', 2)
Create the main route for uploading
app.post('/projects', (req, res) => {
multi_upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
res.status(500).send({ error: { message: `Multer uploading error: ${err.message}` } }).end();
return;
} else if (err) {
// An unknown error occurred when uploading.
if (err.name == 'ExtensionError') {
res.status(413).send({ error: { message: err.message } }).end();
} else {
res.status(500).send({ error: { message: `unknown uploading error: ${err.message}` } }).end();
}
return;
}
// Everything went fine.
// show file `req.files`
// show body `req.body`
res.status(200).end('Your files uploaded.');
})
});
Listen port
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});
HTML code
<form id="form_el" class='new-project' action='/projects' method='POST' enctype="multipart/form-data">
<label for='file'>Select your image:</label>
<input type='file' multiple='multiple' accept='image/*' name='uploadedImages' id='file' />
<span class='hint'>Supported files: jpg, jpeg, png.</span>
<button type='submit'>upload</button>
</form>
JAVASCRIPT CODE
form_el.addEventListener('submit', async function (e) {
const files = e.target.uploadedImages.files;
if (files.length != 0) {
for (const single_file of files) {
data.append('uploadedImages', single_file)
}
}
});
const submit_data_fetch = await fetch('/projects', {
method: 'POST',
body: data
});

Here you go for this example:
var multer = require('multer');
var upload = multer();
router.post('/projects', upload.array('uploadedImages', 10), function(req, res) {
var file = req.files;
res.end();
});
<form action="/projects" method="post" enctype="multipart/form-data">
<input type="file" name="uploadedImages" value="uploading_img" multiple>
<input type="submit" value="uploading_img">
</form>
Visit for more info about Multer.

My guess is that for each file that you want to upload, you reclick:
<input type='file' multiple='multiple' accept='image/*' name='uploadedImages' id='file' />
If you do this, then only the last file selected will be uploaded, as you overwrite the previous selected files.
To upload multiple files, you have to select them all at once in the file picker.

Related

Unexpected behaviour of Multer and Express when field name is wrong

const express = require('express');
const multer = require('multer');
const uuid = require('uuid');
const server = express();
server.use(express.static('client/'));
const upload = multer({
storage: multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'temp/upload/');
},
filename: function (req, file, callback) {
callback(null, uuid.v4().concat('.').concat(file.mimetype.split('/')[1]));
}
}),
fileFilter: function (req, file, callback) {
const whitelist = ['image/jpeg', 'image/png'];
if (whitelist.includes(file.mimetype)) {
callback(null, true);
} else {
callback(null, false);
}
},
}).single('image');
server.post('/api/dummy', (req, res) => {
upload(req, res, async function (error) {
if (error || req.file === undefined) return res.sendStatus(400);
// Doing something, if there is no error.
})
});
server.listen(80);
As you can see, multer expects a file with field name image. Now, if I send a file with correct field name, it gives expected result both from browser and Thunderclient.
Now, I tried to change the field name of the file to anything other than image. Still, Thunderclient works, giving expected result. But browser not getting any response for big images i.e. - 7MB. But surprisingly getting expected result in browser too if the file size is relatively low i.e. - 250KB.
This is the client.
<!DOCTYPE html>
<html>
<body>
<form action="/api/dummy" method="post" enctype="multipart/form-data">
<label for="name">Name</label>
<input type="text" name="name" id="name">
<br>
<label for="logo">Logo</label>
<input type="file" name="logo" id="logo">
<br>
<input type="submit" value="submit">
</form>
</body>
</html>
I have tried with this two random images -
with this image, the browser did not get any response but
with this image, the browser did get the response back.

cant get files using multer in node js (req.file is undefined)

i use multer package with node and react and i send a file to node js backend, but always its undefined..
This is React
<div className="file-field input-field">
<div className="btn">
<span>File</span>
<input
type="file"
name="image"
id="image"
onChange={changedImageUpload}
/>
</div>
<div className="file-path-wrapper">
<input className="file-path validate" />
</div>
</div>
and that is onChange file handling method in there i just get first console.log but second and third is not printed
const changedImageUpload = (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append("image", file);
console.log(formData, file);
try {
const config = {
Headers: {
"Content-Type": "multipart/form-data",
},
};
axios
.post("/uploads", formData, config)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
} catch (err) {
console.log(err);
}
};
and its Node codes and multer configure
import express from "express";
import multer from "multer";
const route = express.Router();
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(
null,
new Date().toISOString().replace(/[\/\\:]/g, "_") + file.originalname
);
},
});
const multerFilter = (req, file, cb) => {
if (
file.mimetype === "image/png" ||
file.mimetype === "image/jpg" ||
file.mimetype === "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({ storage: storage, fileFilter: multerFilter });
route.post("/uploads", upload.single("image"), (req, res) => {
try {
// res.send(`/${req.file.path}`);
console.log(req.file);
} catch (err) {
console.log(err);
}
});
and import in app.js
import uploadRoutes from "./Routes/uploadRoutes.js";
app.use(uploadRoutes);
const __dirname = path.resolve();
app.use("/images", express.static(path.join(__dirname, "/images")));
so at printing formData i always get empty object, and if i print req.file i get an undefined in node js
Your filter function is wrong. You are comparing the mimeType to things like jpg which isn't a real MIME type, so your files are always filtered out.
You need to compare to image/png and image/jpeg instead.

Accepting file and text inputs at the same time with Node.js

I have this form with two types of inputs, file and text. And I trying to save the image file (using Multer) in a local dir. and the text (using mongoose) in the database.
<form
action="publish"
method="POST"
enctype="multipart/form-data"
>
<input type="text" name="textinput" placeholder="Title" />
<input type="file" name="imginput" />
</form>
When i submit the form and try to handle both of the inputs (file & text), it prevents me from accessing the text because of 'enctype="multipart/form-data". I removed the enctype thing, and this time i couldn't access the image file.
async function addText(userInput) {
const text = new Text({ text: userInput });
const result = await text.save();
console.log(result);
};
app.post("/publish", (req, res) => {
// init upload
const upload = multer({
storage: storage,
limits: { fileSize: 1000000 },
fileFilter: (req, file, cb) => {
checkFileType(file, cb);
},
}).single("imginput");
upload(req, res, (err) => {
if (err) {
res.send(err);
} else {
if (req.file == undefined) {
res.send("no file selected");
} else {
res.send("file uploaded");
}
}
});
addText(req.body.textinput);
};
Is there is a way that i can handle both of the inputs?

Nodejs POST a FILE

I'm trying to upload a file from webpage to my backend but nothing happends. There is what i did:
Here's the form from the html file:
<form action="/api/bulk" method="POST" enctype="multipart/form-data">
<div style="width: 200px">
<input
type="file"
id="user_group_logo"
class="custom-file-input"
accept=".xlsx, .xls, .csv"
name="file"
/>
<label id="user_group_label" for="user_group_logo">
<i class="fas fa-upload"></i> Choose a file...
</label>
<button class="btn btn-primary" type="submit">Upload</button>
<div class="text-center"></div>
<div class="text-center mt-2"></div>
</div>
</form>
here's the routing:
router.route('/api/bulk').post(modelController.postBulk);
and here's the controller method that should upload the file to /uploads folder
var multer = require('multer');
const storage = multer.diskStorage({
destination: './uploads',
});
const upload = multer({
storage: storage,
});
exports.postBulk = async (req, res) => {
try {
console.log('test');
upload(req, res, (err) => {
if (err) {
console.log('error');
} else {
console.log(req.file);
res.send('test-req.file');
}
});
} catch (err) {
res.status(404).json({
status: 'fail',
message: err.message,
attention: 'Cannot verify the CSV file. Call support!',
});
}
};
I don't get either a message in the console, so the method is not "accessed" somehow (I should get a "test" when I try to upload the file at least).
Any ideas, please?
Try this
const express = require('express');
const router = express.Router();
const multer = require('multer');
const storage = multer.diskStorage({
destination: './uploads',
});
const upload = multer({
storage: storage,
});
const postBulk = async (req, res) => {
try {
console.log(req.file);
req.status(200).json({})
} catch (err) {
res.status(404).json({
status: 'fail',
message: err.message,
attention: 'Cannot verify the CSV file. Call support!',
});
}
};
router.post(`/api/bulk`, upload.single('file'), postBulk);
try this
router.route('/api/bulk').post(upload.single('file'),modelController.postBulk);
upload is your constant holding multer configuration
.single is for your single file upload and .array is for multiple file upload.
please check req.file inside your controller to get the file uploaded via form

upload multiple files with multer?

I just can't figured whats wrong why my codes below. I try to upload multiple files.
The problem is that i had an "UNEXPECTED FIELD"
I can make it to upload single file just fine, but I can't make it upload multiple files. So what's wrong here?
html
<input id="file" type="file" class="form-control" placeholder="Imagen" name="image" multiple>
component.js
var payload = new FormData();
var files = $('#file')[0].files
for (key in $scope.producto) {
payload.append(key, $scope.producto[key])
console.log($scope.producto[key])
}
if (files.length > 0) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
console.log(file)
console.log(files.length)
payload.append('image', file);
}
}
$http.post('http://localhost:5001/api/v1/articles', payload, {
transformRequest: angular.identity,
headers: { "Content-Type": undefined },
}).then(function (response) {
$location.path("/")
})
Here's the server part:
const multer = require('multer')
const storage = multer.diskStorage({
destination : function(req, file, cb){
cb(null, './uploads/');
},
filename : function(req, file, cb){
cb(null, new Date().toISOString() + file.originalname)
}
})
const upload = multer({storage : storage, limits: {
fileSize : 1024 * 1024 * 5
}})
.post('/api/v1/articles/', upload.array('image', 2 ), controllerArticle.postArticles)
controllerArticle.js
function postArticles(req, res) {
// console.log(req.file)
if (req.file) {
const nvo = new articulos({
name: req.body.name,
price: req.body.price,
condition: req.body.condition,
brand: req.body.brand,
productImage: req.file.path
})
nvo.save((err, productStored) => {
if (err) res.status(500)
res.status(200).send({ nvo: productStored })
})
}
}
I have tried so far:
Change upload.array() to upload.any(),and doesn't work..
any help? thanks!
Already solved... The problem was in the controller.
Is req.files not req.file (singular).
if I just need to upload one file it's req.file and to multiple files is req.files.

Categories

Resources