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: 'zaea#mail.com', phoneNumber: '12345678', …}
coverLetter: "zaez e az ezae e zae aeae "
cv: ""
email: "zaea#mail.com"
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 class="fs-title">Please complete the form below for a position with us.</h2>
<h3 class="fs-subtitle">Reference 0001</h3>
{/* <div class="fs-error"></div> */}
<div class="wrapper">
<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" class="submit action-button" value="Submit" onClick={submit} />
</fieldset>
</form>
</div>
</div>
</div>
)
}
export default Form
I fixed my problem by changing name="myFile" id="cv" to name="cv" id="cv"
Related
I am working on a CRUD application and already have mydata in the useState hook. I prefer not to change it to use formdata just for image upload. I want to use the useState hook for the image {imgUrl} as with my other states
This is the file page I'm using to upload the image.
import { useState, useEffect, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify'
import { createListing } from '../features/listings/listingSlice'
import Spinner from '../components/Spinner'
function CreateListing() {
// eslint-disable-next-line
const [geolocationEnabled, setGeolocationEnabled] = useState(true)
const { user,isLoading } = useSelector((state) => state.auth)
const dispatch = useDispatch()
const [formData, setFormData] = useState({
type: 'rent',
name: '',
bedrooms: 1,
bathrooms: 1,
parking: false,
furnished: false,
location: '',
offer: false,
regularPrice: 0,
discountedPrice: 0,
imgUrl:'',
latitude: 0,
longitude: 0,
})
const {
type,
name,
bedrooms,
bathrooms,
parking,
furnished,
location,
offer,
regularPrice,
discountedPrice,
imgUrl,
latitude,
longitude,
} = formData
const navigate = useNavigate()
const isMounted = useRef(true)
useEffect(() => {
if (isMounted) {
if(user){
setFormData({ ...formData, userRef: user._id })
}else {
navigate('/sign-in')
}
}
return () => {
isMounted.current = false
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMounted])
const onSubmit = async (e) => {
try{
const listingData={
...formData,
}
console.log(listingData)
dispatch(createListing(listingData))
toast.success('Listing saved')
navigate(`/profile`)
} catch(error){
toast.error('Could not add new listing')
}
}
const onMutate = (e) => {
let boolean = null
if (e.target.value === 'true') {
boolean = true
}
if (e.target.value === 'false') {
boolean = false
}
// Files
if (e.target.files) {
setFormData((prevState) => ({
...prevState,
imgUrl: e.target.files,
}))
}
// Text/Booleans/Numbers
if (!e.target.files) {
setFormData((prevState) => ({
...prevState,
[e.target.id]: boolean ?? e.target.value,
}))
}
}
if (isLoading) {
return <Spinner />
}
return (
<div className='profile'>
<header>
<p className='pageHeader'>Create a Listing</p>
</header>
<main>
<form onSubmit={onSubmit}>
<label className='formLabel'>Sell / Rent</label>
<div className='formButtons'>
<button
type='button'
className={type === 'sale' ? 'formButtonActive' : 'formButton'}
id='type'
value='sale'
onClick={onMutate}
>
Sell
</button>
<button
type='button'
className={type === 'rent' ? 'formButtonActive' : 'formButton'}
id='type'
value='rent'
onClick={onMutate}
>
Rent
</button>
</div>
<label className='formLabel'>Name</label>
<input
className='formInputName'
type='text'
id='name'
value={name}
onChange={onMutate}
maxLength='32'
minLength='10'
required
/>
<div className='formRooms flex'>
<div>
<label className='formLabel'>Bedrooms</label>
<input
className='formInputSmall'
type='number'
id='bedrooms'
value={bedrooms}
onChange={onMutate}
min='1'
max='50'
required
/>
</div>
<div>
<label className='formLabel'>Bathrooms</label>
<input
className='formInputSmall'
type='number'
id='bathrooms'
value={bathrooms}
onChange={onMutate}
min='1'
max='50'
required
/>
</div>
</div>
<label className='formLabel'>Parking spot</label>
<div className='formButtons'>
<button
className={parking ? 'formButtonActive' : 'formButton'}
type='button'
id='parking'
value={true}
onClick={onMutate}
min='1'
max='50'
>
Yes
</button>
<button
className={
!parking && parking !== null ? 'formButtonActive' : 'formButton'
}
type='button'
id='parking'
value={false}
onClick={onMutate}
>
No
</button>
</div>
<label className='formLabel'>Furnished</label>
<div className='formButtons'>
<button
className={furnished ? 'formButtonActive' : 'formButton'}
type='button'
id='furnished'
value={true}
onClick={onMutate}
>
Yes
</button>
<button
className={
!furnished && furnished !== null
? 'formButtonActive'
: 'formButton'
}
type='button'
id='furnished'
value={false}
onClick={onMutate}
>
No
</button>
</div>
<label className='formLabel'>Address</label>
<textarea
className='formInputAddress'
type='text'
id='location'
value={location}
onChange={onMutate}
required
/>
{!geolocationEnabled && (
<div className='formLatLng flex'>
<div>
<label className='formLabel'>Latitude</label>
<input
className='formInputSmall'
type='number'
id='latitude'
value={latitude}
onChange={onMutate}
required
/>
</div>
<div>
<label className='formLabel'>Longitude</label>
<input
className='formInputSmall'
type='number'
id='longitude'
value={longitude}
onChange={onMutate}
required
/>
</div>
</div>
)}
<label className='formLabel'>Offer</label>
<div className='formButtons'>
<button
className={offer ? 'formButtonActive' : 'formButton'}
type='button'
id='offer'
value={true}
onClick={onMutate}
>
Yes
</button>
<button
className={
!offer && offer !== null ? 'formButtonActive' : 'formButton'
}
type='button'
id='offer'
value={false}
onClick={onMutate}
>
No
</button>
</div>
<label className='formLabel'>Regular Price</label>
<div className='formPriceDiv'>
<input
className='formInputSmall'
type='number'
id='regularPrice'
value={regularPrice}
onChange={onMutate}
min='50'
max='750000000'
required
/>
{type === 'rent' && <p className='formPriceText'>$ / Month</p>}
</div>
{offer && (
<>
<label className='formLabel'>Discounted Price</label>
<input
className='formInputSmall'
type='number'
id='discountedPrice'
value={discountedPrice}
onChange={onMutate}
min='50'
max='750000000'
required={offer}
/>
</>
)}
<label className='formLabel'>Images</label>
<p className='imagesInfo'>
The first image will be the cover (max 6).
</p>
<input
className='formInputFile'
type='file'
id='images'
onChange={onMutate}
max='6'
accept='.jpg,.png,.jpeg'
multiple
required
/>
<button type='submit' className='primaryButton createListingButton'>
Create Listing
</button>
</form>
</main>
</div>
)
}
export default CreateListing
I added "multipart/form-data" in the header in the createlisting function in my listingService.js file as I read it is required
// Create new listing
const createListing = async (listingData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
'content-type': `multipart/form-data`,
},
}
console.log({listingData})
const response = await axios.post(API_URL, listingData, config)
return response.data
}
Following the documentation, I added Multer in my listingRoutes.js
const express = require('express')
const router = express.Router()
const multer = require('multer')
const upload = multer({ dest: './uploads/' })
const {createListing, getListings, getListing} = require('../controllers/listingController')
const { protect } = require('../middleware/authMiddleware')
router.get('/', protect, getListings)
router.post('/',upload.single('imgUrl'),protect, createListing)
router.get('/:id',protect, getListing)
module.exports = router
For you guys to get the full picture, here is my server.js file
const express = require('express')
const colors = require('colors')
const dotenv = require('dotenv').config()
const {errorHandler} = require('./middleware/errorMiddleware')
const connectDB = require('./config/db')
const PORT = process.env.PORT || 8000
const cors = require('cors')
// Connect to database
connectDB()
const app = express()
app.use(cors());
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.get('/', (req,res) =>{
res.json({message: 'Heloo'})
})
// Routes
app.use('/api/users', require('./routes/userRoutes'))
app.use('/api/listings', require('./routes/listingRoutes'))
app.use(errorHandler)
app.listen(PORT, ()=> console.log(`Server started on port ${PORT}`))
Here is my createlisting function in my listingController.js
const createListing = asyncHandler(async (req,res) =>{
const { bathrooms,bedrooms,discountedPrice,furnished,imgUrl,latitude,longitude,location,name,offer,
parking,regularPrice,timestamp,type,userRef } = req.body
const user = await User.findById(req.user.id)
if (!user){
res.status(401)
throw new Error('User not found')
}
const listing = await Listing.create({
bathrooms,
bedrooms,
discountedPrice,
furnished,
imgUrl,
latitude,
location,
longitude,
name,
offer,
parking,
regularPrice,
timestamp,
type,
userRef: req.user.id
})
console.log({listing})
console.log(listing)
if (listing) {
res.status(201).json({
_id: listing._id,
name: listing.name,
message: 'House has been aded'
})
} else {
res.status(400)
throw new error('Invalid listing data')
}
})
The issue is imgUrl is saved as imgUrl:"[object FileList]" in mongodb and no image is saved in the upload folder. This is my first time using Multer and every documentation/tutorial I have seen uses the formdata interface
First of all see documentation
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
You have
router.post('/',upload.single('imgUrl'),protect, createListing)
...
const { bathrooms,bedrooms,discountedPrice,furnished,imgUrl,latitude,longitude,location,name,offer,
parking,regularPrice,timestamp,type,userRef } = req.body
Secondly file type looks like that (probably you are interested in buffer)
interface File {
/** Name of the form field associated with this file. */
fieldname: string;
/** Name of the file on the uploader's computer. */
originalname: string;
/**
* Value of the `Content-Transfer-Encoding` header for this file.
* #deprecated since July 2015
* #see RFC 7578, Section 4.7
*/
encoding: string;
/** Value of the `Content-Type` header for this file. */
mimetype: string;
/** Size of the file in bytes. */
size: number;
/**
* A readable stream of this file. Only available to the `_handleFile`
* callback for custom `StorageEngine`s.
*/
stream: Readable;
/** `DiskStorage` only: Directory to which this file has been uploaded. */
destination: string;
/** `DiskStorage` only: Name of this file within `destination`. */
filename: string;
/** `DiskStorage` only: Full path to the uploaded file. */
path: string;
/** `MemoryStorage` only: A Buffer containing the entire file. */
buffer: Buffer;
}
I want to refresh my page after save of newRider to Firebase. But when I use window.location.reload(); or with (false) it does not save. Without it it works.
And is it ok to have code that long in one file?
import React from "react";
import { RidersDB } from "../../Backend/DataBase/RidersDB";
const ridersDB = new RidersDB();
export default function CrewMemberSetCreate() {
const [newIsShown, setNewIsShown] = React.useState(false);
const [newRider, setNewRider] = React.useState({
firstName: "",
lastName: "",
age: 0,
favTrick: "",
dreamTrick: "",
youtube: "",
instagram: "",
isShown: newIsShown,
img: "",
});
function handleChange(event) {
setNewRider((prevNewRider) => {
return {
...prevNewRider,
[event.target.name]: event.target.value,
};
});
}
const createRider = (event) => {
event.preventDefault();
ridersDB.createRider({
firstName: newRider.firstName,
lastName: newRider.lastName,
age: Number(newRider.age),
favTrick: newRider.favTrick,
dreamTrick: newRider.dreamTrick,
youtube: newRider.youtube,
instagram: newRider.instagram,
isShown: newIsShown,
img: "",
});
//here i want reload and tried to usewindow.location.reload(false);
};
return (
<div className="setCreate">
<h2>Add Rider</h2>
<div className="centerForm">
<form>
<input
type="text"
placeholder="First Name"
onChange={handleChange}
value={newRider.firstName}
name="firstName"
/>
<input
type="text"
placeholder="Last Name"
onChange={handleChange}
value={newRider.lastName}
name="lastName"
/>
<input
type="number"
placeholder="Age (number)"
min="1"
onChange={handleChange}
value={newRider.age}
name="age"
/>
<input
type="text"
placeholder="Favourite Trick"
onChange={handleChange}
value={newRider.favTrick}
name="favTrick"
/>
<input
type="text"
placeholder="Dream Trick"
onChange={handleChange}
value={newRider.dreamTrick}
name="dreamTrick"
/>
<input
type="text"
placeholder="Youtube Link"
onChange={handleChange}
value={newRider.youtube}
name="youtube"
/>
<input
type="text"
placeholder="Instagram Link"
onChange={handleChange}
value={newRider.instagram}
name="instagram"
/>
<div className="checkboxDiv">
<label>Show on home page?</label>
<input
type="checkbox"
onClick={() => {
setNewIsShown((prevState) => !prevState);
}}
/>
</div>
<button onClick={createRider}>Add Rider</button>
</form>
</div>
</div>
);
}
RidersDB.js
import { db } from "./firebase-config";
import { addDoc, collection, getDocs } from "firebase/firestore";
export class RidersDB {
constructor() {
this.ridersCollRef = collection(db, "ridersCrew");
this.createRider = async (riderData) => {
await addDoc(this.ridersCollRef, riderData);
};
this.getRiders = async () => {
const data = await getDocs(this.ridersCollRef);
return data.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
};
}
}
The createRider() methods returns a Promise. You should wait for it to resolve and then proceed. Try refactoring the code as shown below:
const createRider = (event) => {
event.preventDefault();
return ridersDB.createRider({
firstName: newRider.firstName,
// ....
}).then(() => {
// resolved, proceed now
window.location.reload(false)
}).catch((e) => console.log(e));
};
I currently have a simple next.js website where users can look at projects for an organization, and at the bottom of the page, the user can input a new project through the use of a form with multiple inputs. The database that i am currently using is Supabase.
My code currently takes in user input from each input box and stores them inside the newProject const, after which the data is then parsed into the createNewProject function and sent to Supabase.
const initialState = { solution_id: '', organization_id: '', budget_usd: '',other_info: '',country: '',project_duration_days: '',status: '',date_time_timezone: '' }
export default function Projects({ Projects }) {
useEffect(() => {
console.log(Projects)
}, [])
const [newProject, setProject] = useState(initialState)
console.log("User inputed data")
console.log(newProject)
const {solution_id, organization_id, budget_usd, other_info, country,project_duration_days,status,date_time_timezone} = newProject
const router = useRouter()
function onChange(e) {
setProject(() => ({ ...newProject, [e.target.name]: e.target.value }))
}
async function createNewProject() {
if (!solution_id || !organization_id || !country) return
const id = uuid()
newProject.id = id
const {data} = await supabase
.from('Projects')
.insert([
{ solution_id, organization_id, budget_usd,other_info,country,project_duration_days,status,date_time_timezone }
])
router.push(`/projects/${data.id}`)
}
return (
<div>
{Projects.map(project => {
return (
<div key={project.id}>
<h1><b>{project.Solutions.name} in {project.country}</b></h1>
<h2>Budget USD: {project.budget_usd}</h2>
<h2>Duration: {project.project_duration_days} days</h2>
<h2>Status: {project.status}</h2>
<h2>Organization: {project.Organizations.name}</h2>
<h2>Project Id: {project.id}</h2>
<button type="button" onClick={() => router.push(`/projects/${project.id}`)}>Donate now</button>
<br></br>
</div>
)
})}
<label htmlFor="solution_id ">solution_id</label>
<input onChange={onChange} value={newProject.solution_id} type="text" id="solution_id" name="solution_id" required />
<label htmlFor="organization_id ">organization_id</label>
<input onChange={onChange} value={newProject.organization_id} type="text" id="organization_id" name="organization_id" required />
<label htmlFor="budget_usd ">Last budget_usd</label>
<input onChange={onChange} value={newProject.budget_usd} type="text" id="budget_usd" name="budget_usd" required />
<label htmlFor="other_info ">other_info</label>
<input onChange={onChange} value={newProject.other_info} type="text" id="other_info" name="other_info" required />
<label htmlFor="country ">country</label>
<input onChange={onChange} value={newProject.country} type="text" id="country" name="country" required />
<label htmlFor="project_duration_days ">Project Duration Days</label>
<input onChange={onChange} value={newProject.project_duration_days} type="text" id="project_duration_days" name="project_duration_days" required />
<label htmlFor="status ">status</label>
<input onChange={onChange} value={newProject.status} type="text" id="status" name="status" required />
<label htmlFor="date_time_timezone ">date_time_timezone</label>
<input onChange={onChange} value={newProject.date_time_timezone} type="text" id="date_time_timezone" name="date_time_timezone" required />
<button type="button" onClick={createNewProject} >Submit new project</button>
</div>
)
}
export async function getServerSideProps() {
const fetchOrgs = async () => {
let { data: Organizations, error } = await supabase
.from('Organizations')
.select('*')
return Organizations
}
const fetchSolutions = async () => {
let { data: Solutions, error } = await supabase
.from('Solutions')
.select('*')
return Solutions
}
const fetchProjects = async () => {
let { data: Projects, error } = await supabase
.from('Projects')
.select(`
id,
solution_id,
organization_id,
budget_usd,
country,
project_duration_days,
status,
Solutions(name),
Organizations(name)
`)
.order('id', { ascending: true })
console.log(Projects)
return Projects
}
const Organizations = await fetchOrgs();
const Solutions = await fetchSolutions();
const Projects = await fetchProjects();
return { props: { Solutions, Organizations, Projects } }
}
However, whenever I press the submit button, the console.log for the newProject, would show that there is not data being passed into the variables, only the empty placeholder data in the initialState const. As such, I am unsure about how to pass data from next.js input forms into a variable to be posted into supabase.
I have this fetch where I'm trying to post a form in MongoDB.
When I fill the form I get this back:
SyntaxError: Unexpected end of input at ContactRequest.js:3:1
And I don't know why, because the fetch receives the data from the form and testing the endpoint in postman it works perfectly.
The fetch should works because I used the same Fetch in other projects.
This is the fetch component.
const contactRequest = (params) => {
console.log(`Test ${JSON.stringify(params)}`);
fetch(`http://localhost:4000/contact`, {
method: "POST",
body: JSON.stringify(params),
mode: "no-cors",
headers: {
'Content-Type': 'application/json'
}})
.then(res => res.json())
.catch((e) => console.error(e));
};
export default contactRequest;
This is the form component:
import React, {useState} from 'react';
import contactRequest from '../Request/ContactRequest';
import './Contact.css';
const initialState = {
nameAndSurname: "",
email: "",
phoneNumber: "",
message: "",
};
const Contact = () => {
const [contactData, setContactData] = useState(initialState);
const handlerInput = (e) => {
setContactData({
...contactData,
[e.target.name] : e.target.value
});
};
const handlerSubmit = (e) => {
e.preventDefault();
setContactData(initialState);
contactRequest(contactData);
alert("Hemos recibido tu mensaje.");
}
return (
<div>
<form onSubmit={handlerSubmit}>
<label className="nameAndSurname-label">
Nombre y Apellido: <br/>
<input
id="nameAndSurname"
type="text"
name="nameAndSurname"
placeholder="Ingrese su nombre y apellido"
onChange={handlerInput}
value={contactData.nameAndSurname}
required/> <br/>
</label>
<div className="email-phoneNumber-div">
<label>
Email: <br/>
<input
id="email"
type="email"
name="email"
placeholder="Ingrese su email"
onChange={handlerInput}
value={contactData.email}
required/> <br/>
</label>
<label>
Numero de teléfono: <br/>
<input
id="phoneNumber"
type="number"
name="phoneNumber"
placeholder="Ingrese su numero de teléfono"
onChange={handlerInput}
value={contactData.phoneNumber}
required/> <br/>
</label>
</div>
<label>
Mensaje: <br/>
<input
id="message"
type="text"
name="message"
placeholder="Ingrese su mensaje"
onChange={handlerInput}
value={contactData.message}
required/> <br/>
</label>
<label>
Al enviar este formulario, acepto los terminos y condiciones.
</label>
<button
id="submit-btn"
type="submit"
value="Submit">Enviar</button>
</form>
</div>
</div>
)
}
export default Contact;
This is the Endpoint.
const express = require('express');
const router = express.Router();
const Contact = require('../models/Contact.js');
router.post('/contact', (req, res) => {
console.log(req.body);
console.log(req.text);
let contact = new Contact()
contact.nameAndSurname = req.body.nameAndSurname
contact.email = req.body.email
contact.phoneNumber = req.body.phoneNumber
contact.message = req.body.message
contact.save((err, contactStored) => {
if(err) {
res.status(500).send({message: `Error ${err}`})
}else {
res.status(200).send({contact: contactStored})
}
})
})
module.exports = router;
Why are you using mode: "no-cors"? This results in an "opaque" response, without body, so without anything to convert to json
Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
import React, { useEffect, useState } from 'react';
import axios from "axios"
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
function CreateExercise() {
const [createExercises, setExercise] = useState({
username: "",
description: "",
duration: 0,
date: new Date(),
users: []
});
useEffect(() => {
axios.get('http://localhost:5000/users/')
.then(response => {
if (response.data.length > 0) {
setExercise({
users: response.data.map(user => user.username),
username: response.data[0].username
})
}
})
}, [])
function handleChange(event) {
const { name, value } = event.target;
setExercise(prevExercise => {
return {
...prevExercise,
[name]: value
};
});
}
function changeDate(date) {
setExercise(prevExercise => {
return {
username: prevExercise.username,
description: prevExercise.description,
duration: prevExercise.duration,
date: date,
users: prevExercise.users
};
});
}
function onSubmit(event) {
event.preventDefault();
console.log(createExercises);
axios.post('http://localhost:5000/exercises/add', createExercises)
.then(res => console.log(res.data));
setExercise({
username: "",
description: "",
duration: 0,
date: new Date(),
users: []
});
window.location = '/';
}
return (
<div>
<h3>Create New Exercise log</h3>
<form >
<div>
<label>Username: </label>
<select
required
className="form-control"
value={createExercises.username}
onChange={handleChange}>
{
createExercises.users.map(function (user, index) {
return <option key={user} value={user}>{user}</option>;
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text"
name="description"
className="form-control"
onChange={handleChange}
value={createExercises.description}
/>
</div>
<div className="form-group">
<label>Duration (in minutes): </label>
<input type="text"
name="duration"
className="form-control"
onChange={handleChange}
value={createExercises.duration}
/>
</div>
<div className="form-group">
<label>Date: </label>
<DatePicker
selected={createExercises.date}
onChange={changeDate}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary" onClick={onSubmit} >Create Exercise Log</button>
</div>
</form>
</div>
);
}
export default CreateExercise;
how can i avoid above console error occured?
I think your problem is in your effect, particularly in the way you use setExercise, when you do:
setExercise({
users: response.data.map(user => user.username),
username: response.data[0].username
})
It doesn't "merge" (assign) the new data with previous state, what it does - is just sets the state, meaning your state object after this will be:
{ users:[], username:''}
So you actually lose description and other fields - hence the warning.
What you should do, is this:
setExercise((prevState) => ({
...prevState,
users: response.data.map(user => user.username),
username: response.data[0].username
}))