I'm building a form using React & Nodejs & MongoDB, where you can fill the form and upload a file with some other text inputs.
However, after i submit, i receive only text inputs in my database. The chosen file (desired to upload) doesn't appear at all in the database. I am expecting to get all the data form (the uploaded file and text inputed) in my database.
I tested my backend and it works correctly (it uploads all the inputs).
Ps: In browser, when i select a file (.pdf) to upload, the file input always shows no file chosen !
Console.dev : Error
{title: 'Miss', fname: 'zaezae', lname: 'zaeazee', email: '[email protected]', phoneNumber: '12345678', …}
coverLetter: "zaez e az ezae e zae aeae "
cv: ""
email: "[email protected]"
fname: "zaezae"
lname: "zaeazee"
myFile: "C:\\fakepath\\test.pdf"
phoneNumber: "12345678"
title: "Miss"
Formulaire.jsx:29
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'then')
at submit (Formulaire.jsx:29:1)
Backend:
server.js:
const express = require('express')
const mongoose = require('mongoose')
const bodyparser = require('body-parser')
const FormRoute = require('./routes/FormRoute')
//database
mongoose.connect('mongodb://localhost:27017/form', { useNewUrlParser: true, useUnifiedTopology: true })
const db = mongoose.connection
db.on('error', (err) => {
console.log(err)
})
db.once('open', () => {
console.log("Database connection established!")
})
//app
const app = express()
app.use(bodyparser.urlencoded({ extended: true }))
app.use(bodyparser.json())
//cors
const cors = require('cors')
app.use(cors())
//server run
const PORT = process.env.PORT || 5000
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
})
app.use('/api/form', FormRoute);
Axios.js:
import axios from 'axios'
export const Axios = axios.create({
baseURL: 'http://localhost:5000',
})
Apiroutes.js:
const form = "/api/form"
export const requests = {
formApi: {
store: form '/store'
}
}
formservices.js:
import { Axios } from "../config/axios";
import { requests } from "../config/apiroutes";
export const FormService = {
store: (data) => {
Axios.post(requests.formApi.store, data)
.then(res => {
return res
})
.catch(err => {
return err
})
}
}
formController.js :
const form = require('../models/FormModel')
const store = (req, res, next) => {
let candidate = new form({
title: req.body.title,
fname: req.body.fname,
lname: req.body.lname,
email: req.body.email,
phoneNumber: req.body.phoneNumber,
coverLetter: req.body.coverLetter
})
if (req.file) {
candidate.cv = req.file.path
}
candidate.save()
.then(response => {
res.json({
success: true,
message: 'Candidate added successfully!',
data: candidate,
})
})
.catch(error => {
res.json({
success: false,
message: 'An error occured!',
error: error,
})
})
}
module.exports = {
store
}
Frontend:
Formulaire.jsx :
import React, { useState } from 'react'
import Divider from '@mui/material/Divider';
import './Formulaire.css'
import { titles } from '../../mock/titles'
import { FormService } from '../../services/formServices';
const Form = () => {
const [storedata, setstoredata] = useState({
title: '',
fname: '',
lname: '',
email: '',
phoneNumber: '',
cv: '',
coverLetter: ''
})
const handleChange = e => {
const { name, value } = e.target;
setstoredata(prevState => ({
...prevState,
[name]: value
}));
};
const submit = async () => {
console.log(storedata);
await FormService.store(storedata)
.then(res => {
console.log(res);
})
.catch(err => {
return err
})
}
return (
<div className='container'>
<div className='header'>
<div className='title'>
<a className='quizbutton' href="/quiz">Take a Test (Quiz)</a>
<h1>Apply for a Position :</h1>
</div>
</div>
<Divider style={{ maxWidth: '1000px', marginLeft: '250px' }} />
<div id="content">
<div id="formWrapper">
<form id="msform" method='post' action='/uploadFile' enctype="multipart/form-data">
<fieldset id="fieldset3">
<h2 >Please complete the form below for a position with us.</h2>
<h3 >Reference 0001</h3>
{/* <div ></div> */}
<div >
<label for="title">Title :</label>
<select name="title" value={storedata.title} onChange={handleChange}>
<option hidden></option>
{
titles.map((c, i) => {
return (
<option key={i} value={c}>{c}</option>
)
})
}
</select>
<label for="fname">First Name<span>*</span> :</label>
<input type="text" name="fname" value={storedata.fname} onChange={handleChange} id="fname" placeholder="Please enter your first name" required />
<label for="lname">Last Name<span>*</span> :</label>
<input type="text" name="lname" value={storedata.lname} onChange={handleChange} id="lname" placeholder="Please enter your last name" required />
<label for="email">Email<span>*</span> :</label>
<input type="email" name="email" value={storedata.email} onChange={handleChange} id="email" placeholder="Please enter your email" required />
<label for="phoneNumber">Phone N° :</label>
<input type="number" name="phoneNumber" value={storedata.phoneNumber} onChange={handleChange} id="phoneNumber" placeholder="Phone number" />
<label for="CV">Upload CV <span>*</span>:</label>
<input type="file" name="myFile" id="cv" value={storedata.cv} onChange={handleChange} accept="application/msword, application/pdf" placeholder="Cover Letter" required />
<label for="coverLetter">Cover Letter :</label>
<textarea type="text" name="coverLetter" value={storedata.coverLetter} onChange={handleChange} id="coverLetter" placeholder="cover Letter" />
</div>
<br />
<input type="submit" name="submit" value="Submit" onClick={submit} />
</fieldset>
</form>
</div>
</div>
</div>
)
}
export default Form
CodePudding user response:
The error is because you are not waiting to axios to respond. You have to return a promise here:
export const FormService = {
store: (data) => {
return new Promise((resolve, reject) => {
Axios.post(requests.formApi.store, data)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err)
})
}
}
}
Or you can use async await if you prefer.
The thing that i dont understand is if you are trying to send the file or just its name. If you want to upload the file you have to send the event.target.files
(like this: https://www.geeksforgeeks.org/file-uploading-in-react-js/)
And use a middleware like express-fileupload or multer in the server.
CodePudding user response:
I fixed my problem by changing name="myFile" id="cv"
to name="cv" id="cv"