19

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);
});
Zeinab
  • 389
  • 4
  • 14
Runny Yolk
  • 1,074
  • 3
  • 23
  • 41

3 Answers3

21

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
});
Aman Silawat
  • 501
  • 4
  • 8
  • Thank you so much. I've been fighting with this for the last 4 hours. The individual appends was what I was searching for. – Julian Mar 22 '22 at 14:08
  • thank you, here is how to use the `multer().array()` method: https://github.com/expressjs/multer#arrayfieldname-maxcount – arrmani88 May 28 '22 at 08:26
  • in the callback filename you change the originalfilename (with Date.now().. ) and save it to the disk, but how can I get that new name further in my route? since req.files has still the original file names and not the new ones set by you! – Suisse Jun 23 '22 at 15:38
12

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.

O'Neil
  • 3,790
  • 4
  • 16
  • 30
Noman
  • 1,459
  • 2
  • 18
  • 38
  • Thanks Syed, but I just tried this and get this error in console: error `[Function: next] [ { fieldname: 'uploadedImages', originalname: 'Me.jpg', encoding: '7bit', mimetype: 'image/jpeg', buffer: , size: 98305 } ]` – Runny Yolk Sep 06 '16 at 13:43
  • Have you tried only my example or apply your code as well ? – Noman Sep 06 '16 at 13:45
  • I just added the code I tried to my original post. Same as yours more or less, but it isn't working. – Runny Yolk Sep 06 '16 at 14:01
4

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.

Mathias
  • 73
  • 7
  • Hey your answer helped me, just need to ask what if i want the user to upload every file on click, how could i then prevent this default behaviour? – Emma Mar 09 '20 at 20:32