i have an uncontrolled form in react in which i'm supposed to upload a video and multiple images, i keep getting the "unexpected field" error despite matching the names in my data object and in the multer upload function
the react code looks like this
function handleSubmit(e) {
e.preventDefault();
let newObject = {
name: e.target["name"].value,
tags: e.target["tags"].value,
address: e.target["address"].value,
images: e.target["images"].files,
video: e.target["video"].files[0],
description: e.target["description"].value
}
axios.post("/api/uploadInfo", newObject, { headers: { "Content-Type": "multipart/form-data" } }).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
}
function FormGroup({ name, id, type, text, required, accept, multiple }) {
return (
<div className="form-group my-3 mx-auto">
<label className="form-label m-0 text-main text-start fs-4" htmlFor={id}>{text}</label>
<input className="form-control ms-1" required={required} type={type} name={name} id={id} accept={accept ? accept : ""} multiple={multiple ? multiple : false}/>
</div>
)
}
<form onSubmit={handleSubmit} className="">
<FormGroup name="name" id="name" type="text" text={text} required={true} />
<FormGroup name="tags" id="tags" type="text" text={text} required={true} />
<FormGroup name="address" id="address" type="text" text={text} required={true} />
<FormGroup name="images" id="images" type="file" text={text} accept="image/*" required={false} multiple={true} />
<FormGroup name="video" id="video" type="file" text={text} accept="video/mp4,video/x-m4v,video/*" required={false} />
<div className="my-5 mx-auto w-50">
<label className="form-label text-main fs-3" htmlFor="msg">{text}</label>
<textarea className="form-control" required="required" name="description" id="description" rows="8" ></textarea>
</div>
<button className="btn btn-lg w-25 mt-5">{text}</button>
</form>
on my backend the multer and router code look like this
const multer = require("multer");
const { v4: uuidv4 } = require('uuid');
const fs = require("fs");
const router = express.Router();
const DIR = './uploads/videos/';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
fs.mkdirSync(DIR, { recursive: true });
cb(null, DIR);
},
filename: (req, file, cb) => {
const fileName = file.originalname.toLowerCase().split(' ').join('-');
cb(null, uuidv4() '-' fileName)
}
});
let vidUpload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype == "video/mp4") {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only video format allowed!'));
}
}
});
const imagesDIR = './uploads/images/';
const imagesStorage = multer.diskStorage({
destination: (req, file, cb) => {
fs.mkdirSync(imagesDIR, { recursive: true });
cb(null, imagesDIR);
},
filename: (req, file, cb) => {
const fileName = file.originalname.toLowerCase().split(' ').join('-');
cb(null, uuidv4() '-' fileName)
}
});
let imagesUpload = multer({
storage: imagesStorage,
fileFilter: (req, file, cb) => {
if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "image/jpeg") {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
}
}
});
router.post("/newInfo", imagesUpload.array("images",8), vidUpload.single('video'), (req, res) => {
console.log(req.body);
res.sendStatus(200);
})
i've faced no problems with uploading the video, but it seems that the images field keeps returning "unexpected field error", i tested it by trying to remove the images upload MW and then the video uploads fine on its own, but when i removed the video MW the images just keep giving me this error..what am i doing wrong?
CodePudding user response:
Man we really learn the most when we fix our issues ourselves..as commented above i traced the issue and found that i can't store multiple files in list/array and send that to multer..instead of using a normal js object use a FormData object where you can loop over each file in the file list and append it under the same key..i don't understand how they don't override each other but it works alright, in the code in the post just replace the object code with this and you're done
let formData = new FormData();
formData.append('name', e.target["name"].value);
formData.append('tags', e.target["tags"].value);
formData.append('address', e.target["address"].value);
formData.append('description', e.target["description"].value);
formData.append('video', e.target["video"].files[0]);
let imgFiles = e.target["images"].files;
for (let i = 0; i < imgFiles.length; i ) {
formData.append('images', imgFiles[i]);
}
and send the formData in the body of the post request