0
votes

Error:

TypeError: Cannot destructure property 'firstName' of 'req.body.warranty' as it is undefined.

I tried to handle MulterError by this documentation https://www.npmjs.com/package/multer, but faced a problem.

Console.log(req.body) gives { }, while form enctype is equal to 'multipart/form-data'. If I change it to the 'application/x-www-form-urlencoded' req.body is normal, but files do not upload to the server.

Multer Usage

var storage = multer.diskStorage({
  destination:"./public/uploads/",
  filename:(req,file,cb)=>{
    cb(null,file.fieldname+"-"+Date.now()+path.extname(file.originalname));
  }
});

var upload = multer({
  storage: storage,
  limits:{fileSize: 10000000}
}).fields([{
           name: 'purchasePhoto', maxCount: 1
         }, {
           name: 'defectPhoto', maxCount: 1
         }]);

Post route from the warranty page with a form enctype="multipart/form-data"

router.post("/warranty", function(req, res){

  upload(req, res, function (err) {
    if (err instanceof multer.MulterError) {
      req.flash('error', 'Multer Error');
      return res.redirect('/pages/warranty#flash');
    } else if (err) {
      console.log('error');
    }
  });

 var  { firstName, lastName, streetAdress, city, state, zip, country, email, phoneNumber, product, bikeShop, assembledBy, issue} = req.body.warranty;

   var newWarranry = { purchasePhoto: purchasePhoto, defectPhoto: defectPhoto, firstName: firstName, lastName: lastName, streetAdress: streetAdress, city: city, state: state, zip: zip, country: country, email: email, phoneNumber: phoneNumber, product: product, bikeShop: bikeShop, assembledBy: assembledBy, issue: issue};
   
  if ( !firstName || !lastName || !streetAdress || !city || !state || !zip || !country || !email || !phoneNumber || !product || !bikeShop || !assembledBy ) {
    req.flash('error', 'Please enter all of the fields with "*"');
    return res.redirect('/pages/warranty#flash');
  } else{
    Warranty.create(newWarranry, function(err, newWarranry){
      if(err){
          console.log(err);
      }else{
         console.log(newWarranry);
         req.flash('success', 'Thank you! The form was submitted successfully.');
         return res.redirect('/pages/warranty#flash');
      }
    });
  } 
});

Warranty page form with a action="warranty" method="post" and enctype="multipart/form-data". All inputs with a name="warranty[...]"

<form action="warranty" method="post" enctype="multipart/form-data">
    <b>Warranty Claim Form</b>
    <h6>Rider Info</h6>
    <div class="row">
        <div>
            <input type="" name="warranty[firstName]" placeholder="First Name*">
        </div>
        <div>
            <input type="" name="warranty[lastName]" placeholder="Last Name*">
        </div>
        <div>
            <input type="" name="warranty[streetAdress]" placeholder="Street Adress*">
        </div>
        <div>
            <input type="" name="warranty[streetAdressLine]" placeholder="Street Adress Line 2">
        </div>
        <div>
            <input name="warranty[city]" placeholder="City*">
        </div>
        <div>
            <input type="" name="warranty[state]" placeholder="State/Province*">
        </div>
        <div>
            <input type="" name="warranty[zip]" placeholder="ZIP/Postal code*">
        </div>
        <div>
            <input type="" name="warranty[country]" placeholder="Country*">
        </div>
        <div>
            <input type="" name="warranty[email]" placeholder="Email*">
        </div>
        <div>
            <input type="" name="warranty[phoneNumber]" placeholder="Phone Number*">
        </div>
    </div>
        <h6>Product Details</h6>
    <div class="row">
        <div>
            <input name="warranty[product]" placeholder="Product (Ex. Titan II Frame)*">
        </div>
        <div>
            <input type="" name="warranty[color]" placeholder="Color (Ex. Black)">
        </div>
        <div>
            <input type="" name="warranty[size]" placeholder="Size (Ex. 20.5in / 175mm)">
        </div>
        <div>
            <input type="" name="warranty[serialNumber]" placeholder="Serial number or date code (bikes, frames, forks, bars, cranks only)">
        </div>
    </div>
    <h6>PURCHASE & ASSEMBLY DETAILS</h6>
    <div class="row">
        <div >
            <input name="warranty[bikeShop]" placeholder="Bike Shop or online retailer*">
        </div>
        <div>
            <input type="" name="warranty[modelYear]" placeholder="Model year (Ex.2015)">
        </div>
        <div >
            <input type="" name="warranty[assembledBy]" placeholder="Assembled by myself/ bike shop">
        </div>
    </div>
    <h6>PRODUCT ISSUE/DEFECT INFORMATION</h6>
    <div class="row">
        <div>
            <textarea name="warranty[issue]"></textarea>
        </div>
    </div>
    <h6>UPLOAD PROOF OF PURCHASE OR RECEIPT (SCAN OR MOBILE PHOTO)</h6>
    <div>
     
    <input type="file" name="purchasePhoto" id="fileOne">
    <label for="fileOne">
      <span>Upload file</span>
    </label>
   
  </div>
    <h6>UPLOAD PRODUCT IMAGES, INCLUDING IMAGES OF DEFECTS</h6>
    <div class="form-group">
    
    <input type="file" name="defectPhoto" id="fileTwo">
    <label for="fileTwo">
      <span>Upload file</span>
    </label>
  </div>
  <div>
    <button type="submit"><p>Submit</p></button>
  </div>
</form>
3

3 Answers

0
votes

Move your code up into the multer callack

router.post("/warranty", function(req, res) {
  upload(req, res, function(err) {
    if (err) {
      req.flash("error", "Multer Error");
      return res.redirect("/pages/warranty#flash");
    }
    var {
      firstName,
      lastName,
      streetAdress,
      city,
      state,
      zip,
      country,
      email,
      phoneNumber,
      product,
      bikeShop,
      assembledBy,
      issue
    } = req.body.warranty;

    var newWarranry = {
      purchasePhoto: purchasePhoto,
      defectPhoto: defectPhoto,
      firstName: firstName,
      lastName: lastName,
      streetAdress: streetAdress,
      city: city,
      state: state,
      zip: zip,
      country: country,
      email: email,
      phoneNumber: phoneNumber,
      product: product,
      bikeShop: bikeShop,
      assembledBy: assembledBy,
      issue: issue
    };

    if (
      !firstName ||
      !lastName ||
      !streetAdress ||
      !city ||
      !state ||
      !zip ||
      !country ||
      !email ||
      !phoneNumber ||
      !product ||
      !bikeShop ||
      !assembledBy
    ) {
      req.flash("error", 'Please enter all of the fields with "*"');
      return res.redirect("/pages/warranty#flash");
    } else {
      Warranty.create(newWarranry, function(err, newWarranry) {
        if (err) {
          console.log(err);
        } else {
          console.log(newWarranry);
          req.flash(
            "success",
            "Thank you! The form was submitted successfully."
          );
          return res.redirect("/pages/warranty#flash");
        }
      });
    }
  });
});
0
votes

The problem is not with the way we send data, rather the multer library is unable to parse out the mutiple files from the form.

use multer.array method and it should work as expecteed, I tried out the same example you gave it seems to be working as expected.

Inside app.js, use app.use(upload.array()), where upload is an instance of multer.

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
let bodyParser = require('body-parser');

//******* require multer library ******
var multer = require('multer');
var upload = multer();

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// ***** this line important
app.use(upload.array()); 


app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

This will resolve the issue!!

0
votes

My problem was that I used

app.use(bodyParser.urlencoded({extended: true}));

But I had to use

app.use(bodyParser.urlencoded({extended: false}));