I'm trying to upload images to the backend using base64, my upload is fine, but the backend receives an empty string. When I use console log, I get the data. I don't know what went wrong here.
export default function NewPost() {
const [title, setTitle] = useState("");
const [file, setFile] = useState("");
const [baseImage, setBaseImage] = useState("");
const [newPost, setNewPost] = useState({
userId: '',
title: '',
content: '',
photo: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post("/posts/", newPost);
window.location.replace("/post/" + res.data._id);
console.log('Saved Successfully');
} catch (err) {
console.log(err);
}
}
const uploadImage = async (e) => {
const file = e.target.files[0];
const base64 = await convertBase64(file);
setBaseImage(base64);
console.log(base64);
setNewPost({ ...newPost, photo: baseImage });
};
const convertBase64 = (file) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
resolve(fileReader.result);
};
fileReader.onerror = (error) => {
reject(error);
};
});
};
return (
<div className="newPostPageContainer">
<form className="newPostForm" onSubmit={handleSubmit}>
<div className="newPostTitleImageUploadCont">
<div className="newPostTitleContainer">
<label className="newPostFormLabel">Post Title:</label>
<input dir="auto" type="text"
onChange={e => setNewPost({ ...newPost, title: e.target.value })} />
</div>
<div className="newPostUploadImgContainer">
<img src={baseImage} alt="" className="newPostUploadImg" />
<label for="file">
<PublishIcon />
</label>
<input
type="file"
id="file"
onChange={(e) => { uploadImage(e); }}
style={{display: "none"}} />
</div>
</div>
<button className="newPostCreateButton" type="submit">
<p className="newPostCreateButtonText">Create</p>
</button>
</form>
</div>
);
}
Before that I used <FileBase64 /> and it was working perfectly. But since it can't be customized I changed to this, trying to do my own function, some help here would be appreciated.
Related
I want to create multiple dynamic fields for searching (so I can add or subtract text fields to write the search), here's my code on the backend to find the requestor and the frontend which is still not integrated with the backend (I still following the tutorial steps to create a form whose fields are dynamic)
how do I get the two parts to be properly integrated and can produce data search results when pressing the handlesubmit button?
here I use react JS, node JS, express, and MySQL
thanks
for backend
export const getRequestor = async (req: TypedRequestQuery<{lastId: string, search_requestor:string}>, res: Response) =>{
const searchRequestor = req.query.search_requestor || "";
const resultRequestor = await Product.findAll({
where:{
[Op.or]: [
{title_dev:{ //requestor
[Op.like]: '%'+searchRequestor+'%'
}}]
},
order:[
['id_project', 'ASC']
]
});
res.json({
resultRequestor: resultRequestor,
});
}
for frontend
const Audit = () => {
const [requestors, setRequestors] = useState([]);
const [keyword, setKeyword] = useState("");
const [query, setQuery] = useState("");
useEffect(() => {
getRequestor();
}, [keyword]);
const getRequestor = async () => {
const response = await axios.get(
`http://localhost:5001/requestor?search_requestor=${keyword}`
);
setRequestors(response.data.resultRequestor);
};
const [inputFieldsRequestor, setInputFieldsRequestor] = useState([
{idRequestor: uuidv4(), requestor: ''},
]);
const handleSubmitRequestor = (e) => {
e.preventDefault();
console.log("InputFieldsRequestor", inputFieldsRequestor);
};
const handleSubmitAll = (e) => {
e.preventDefault();
console.log("InputFieldsRequestor", inputFieldsRequestor);
console.log("InputFieldsPeriod", inputFieldsPeriod);
};
const handleChangeInputRequestor = (idRequestor, event) => {
const newInputFieldsRequestor = inputFieldsRequestor.map(i => {
if(idRequestor === i.idRequestor){
i[event.target.name] = event.target.value
}
return i;
})
setInputFieldsRequestor(newInputFieldsRequestor);
}
const handleAddFieldsRequestor = () =>{
setInputFieldsRequestor([...inputFieldsRequestor, {idRequestor: uuidv4(), requestor:''}])
// setRequestors([...requestors]);
}
const handleRemoveFieldsRequestor = idRequestor => {
const values = [...inputFieldsRequestor];
values.splice(values.findIndex(value => value.idRequestor === idRequestor), 1);
setInputFieldsRequestor(values);
}
const submitrequestor= (e) =>{
e.preventDefault();
setKeyword(query);
console.log("Requestor", requestors);
}
return(
<div>
<form className='form-horizontal' onSubmit={handleSubmitRequestor}>
{inputFieldsRequestor.map(inputFieldRequestor => (
<div key={inputFieldRequestor.idRequestor}>
<div className="form-group row">
<label className="col-sm-2 col-form-label">Requestor</label>
<div className="col-sm-10">
<input type="text"
name="requestor"
className="form-control"
variant="filled"
value={inputFieldRequestor.requestor}
onChange={event => handleChangeInputRequestor(inputFieldRequestor.idRequestor, event)}
placeholder="Requestor" />
<button className="offset-sm-1 col-sm-2" disabled={inputFieldsRequestor.length === 1}
onClick={() => handleRemoveFieldsRequestor(inputFieldRequestor.idRequestor)}>
-
</button >
<button className="offset-sm-1 col-sm-2" onClick={handleAddFieldsRequestor}>
+
</button>
</div>
</div>
</div>
))}
<button
className="btn btn-danger"
type='submit'
onClick={handleSubmitRequestor}
>
send
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>)}
I wanted to upload images and display the image which was chosen, How to display the image after choosing. this is my code, help me display the image, I made the function to post the image, I can post multiple images in one click but i can't display the image to preview before upload , i try to use file reader but cannot display and upload.
const [pImg, setPImg] = useState([]);
const [images, setImages] = useState([]);
const addImg = (ImagesPostDto) => {
const data2 = new FormData();
[...ImagesPostDto].forEach((Images) => {
data2.append("ImagesPostDto", Images);
});
Axios.post(`/shop/${shopID}/Product/${pID}/Images`, data2)
.then((res) => {
if (res.status === 200) {
setMessage({
data: `${res.data.MESSAGE}`,
type: "alert-success",
});
onShowAlert();
}
})
.catch((err) => {
setMessage({
data: `${err.response.data.MESSAGE}`,
type: "alert-danger",
});
setLoading(false);
onShowAlert();
});
};
const handleImageChange = (e) => {
e.preventDefault();
const ProductImg = e.target.files;
setPImg(ProductImg);
const reader = new FileReader();
reader.onloadend = () => {
setPImg(ProductImg);
setImages(reader.result);
};
reader.readAsDataURL(ProductImg);
};
const handleProductSubmit = (event) => {
event.preventDefault();
addImg(pImg);
};
return (
<div>
<Form>
<p>
<Label htmlFor="file">Upload images</Label>
<input
type="file"
id="file"
onChange={handleImageChange}
accept="image/png, image/jpg, image/jpeg"
multiple
/>
</p>
</Form>
<div className="">
{/* {images.length > 0 ? (
<div>
{images.map((image) => (
<p>
<img src={images} alt="" />
</p>
))}
</div>
) : null} */}
</div>
If you want to render images then, create ObjectURL from files array and set the images State then it should work fine. I have commented the code related to API call so that we can focus on rendering the selected images.You can just simply copy this code and paste it in CodeSandBox it should work fine Here is your code a bit modified:
import "./styles.css";
import { useState } from "react";
export default function App() {
const [pImg, setPImg] = useState([]);
const [images, setImages] = useState([]);
// const addImg = (ImagesPostDto) => {
// const data2 = new FormData();
// [...ImagesPostDto].forEach((Images) => {
// data2.append("ImagesPostDto", Images);
// });
// Axios.post(`/shop/${shopID}/Product/${pID}/Images`, data2)
// .then((res) => {
// if (res.status === 200) {
// setMessage({
// data: `${res.data.MESSAGE}`,
// type: "alert-success"
// });
// onShowAlert();
// }
// })
// .catch((err) => {
// setMessage({
// data: `${err.response.data.MESSAGE}`,
// type: "alert-danger"
// });
// setLoading(false);
// onShowAlert();
// });
// };
const handleImageChange = (e) => {
e.preventDefault();
console.log("event", e);
const ProductImg = [...e.target.files];
const images = ProductImg.map((image) => URL.createObjectURL(image));
console.log("images", images);
setImages(images);
};
// const handleProductSubmit = (event) => {
// event.preventDefault();
// addImg(pImg);
// };
return (
<div>
<form>
<p>
<label htmlFor="file">Upload images</label>
<input
type="file"
id="file"
onChange={handleImageChange}
accept="image/png, image/jpg, image/jpeg"
multiple
/>
</p>
</form>
<div className="">
{images.length > 0 && (
<div>
{images.map((image, index) => (
<p key={index}>
<img src={image} alt="" />
</p>
))}
</div>
)}
</div>
</div>
);
}
You need to fetch the Images from GET API and set the response in setImages than it will show right now the images variable is empty array.
As far I can understand your requirement, you need to preview the Images Either when you have selected or After uploaded.
What you can do is, whenever you are preparing the FormData or at the time of change event, you can store each selected file's ObjectURL in another state and Easily can display these images via the State.
This is for api re-rendering issue, I want to know that how to call one api after selecting a dropdown option.
Here it re-render infinite time after selecting an-option in drop-down. I call an client Api from client collection and show in client drop down after I select drop down and going to the infinite loop.
import Select from "react-select";
import Axios from "axios";
import React, { useState, useEffect } from "react";
export default function Form() {
const [hday, setHday] = useState(null);
const [date, setDate] = useState(null);
const [hdata, setHdata] = useState([]);
const [hid, setHid] = useState(""); //changed use state value null to []
const [client, setClient] = useState([]);
const [clientvalue, setClientValue] = useState(null);
const [clientId, setClientId] = useState(""); //changed use state value null to []
const [cemail, setCemail] = useState([]);
const [clientname, setClientname] = useState(null);
const [clientEmail, setClientEmail] = useState([]);
const [message, setMessage] = useState("");
const [fromField, setFromField] = useState("");
const [loading, setLoading] = useState(false);
const handleRequest = async (e) => {
if (clientvalue && hday && fromField && cemail && clientEmail && message !== "") {
if (message !== "") {
e.preventDefault();
setLoading(true);
console.log({
clientvalue,
hday,
fromField,
cemail,
clientEmail,
message,
});
const body = {
clientvalue,
hday,
fromField,
cemail,
clientEmail,
message,
};
await Axios.post("http://localhost:3002/mail", body, {
headers: {
"Content-type": "application/json",
},
})
.then((res) => {
alert("Email Sent Successfully");
setLoading(false);
console.log(res);
window.location.reload();
})
.catch((err) => {
console.log(err);
setLoading(false);
});
} else {
alert("Compose Email");
}
} else {
alert("Please fill all required filled");
}
};
const fromFieldChange = (obj) => {
setFromField(obj.target.value);
};
const handleQuillChange = (e) => {
setMessage(e.target.value);
};
function handleHolidayChange(obj) {
console.log("This is object country", obj);
setHday(obj);
setHid(obj._id);
setDate(null);
}
//client call (repetadely call)
const onChangeClient = (obj) => {
console.log("client object", obj);
console.log("client object id", obj._id);
setClientValue(obj);
setClientId(obj._id);
setClientname(obj.client_name);
};
// console.log("This is client id and name", clientId + " " + clientname);
//(issues repetadely execute)
async function emailClick() {
const url = `http://localhost:3002/api/getClientEmail/${clientId}/${clientname}`;
Axios.get(url)
.then((response) => {
const temp = response.data.map((e) => e.email);
setCemail(temp);
console.log("Client Email", cemail);
})
.catch((error) => {
console.log(error);
});
}
emailClick();
const changeDate = async function dateClick() {
const url = `http://localhost:3002/api/holiday_date/${hid}`;
await Axios.get(url)
.then((response) => {
// console.log("This is holiday date",response.data[0]['date_of_holiday']);
setDate(response.data.date_of_holiday);
// console.log("holiday year",date);
})
.catch((error) => {
console.log(error);
});
};
changeDate();
useEffect(
() => {
async function getHoliday() {
const url = `http://localhost:3002/api/holidays`;
await Axios.get(url)
.then((response) => {
setHdata(response.data);
console.log("this is holiday", response.data);
})
.catch((err) => {
console.log(err);
});
}
getHoliday();
async function getClient() {
const url = `http://localhost:3002/api/client`;
await Axios.get(url)
.then((response) => {
setClient(response.data);
console.log("this is client", response.data);
})
.catch((err) => {
console.log(err);
});
}
getClient();
///api/emailtemplates
async function getClientEmail() {
const url = `http://localhost:3002/api/emailtemplates`;
await Axios.get(url)
.then((response) => {
setClientEmail(response.data.map((e) => e.subject));
})
.catch((err) => {
console.log(err);
});
}
getClientEmail();
},
[date],
[cemail],
);
return (
<form onSubmit={handleRequest} method="post">
<div className="form">
<div className="form__wrapper">
<div className="form__title">
{/* title */}
<h4>Holiday</h4>
</div>
<div className="form__container">
<div className="form__containerItems">
<div className="form__containerItem">
<div className="form__containerItemName">
<label>Client</label>
</div>
<div className="form__containerItemField">
<Select
onChange={onChangeClient}
placeholder="Select Client"
value={clientvalue}
options={client}
getOptionLabel={(x) => x.client_name}
getOptionValue={(x) => x._id}
/>
</div>
</div>
<div className="form__containerItem">
<div className="form__containerItemName">
<label>Holiday</label>
</div>
<div className="form__containerItemField">
<Select
onChange={handleHolidayChange}
placeholder="Select Holiday"
value={hday}
options={hdata}
getOptionLabel={(x) => x.holiday_name}
getOptionValue={(x) => x._id}
/>
</div>
</div>
<div className="form__containerItem">
<div className="form__containerItemName">
<label>Date</label>
</div>
<div className="form__containerItemField">
<input type="text" placeholder="date..." defaultValue={date} />
</div>
</div>
</div>
</div>
<div className="form__container">
<div className="form__containerItems">
{/* from */}
<div className="form__containerItem">
<div className="form__containerItemName">
<label>From</label>
</div>
<div className="form__containerItemField">
<input
type="email"
placeholder="Sender Email.."
// autoFocus="autoFocus"
value={fromField}
onChange={fromFieldChange}
/>
</div>
</div>
{/* to */}
<div className="form__containerItem">
<div className="form__containerItemName">
<label>To</label>
</div>
<div className="form__containerItemField">
<input type="text" placeholder="Client Emial.." defaultValue={cemail} />
</div>
</div>
{/* Subject */}
<div className="form__containerItem">
<div className="form__containerItemName">
<label>Subject</label>
</div>
<div className="form__containerItemField">
<input type="text" placeholder="Write your Sub..." defaultValue={clientEmail} />
</div>
</div>
<div className="form__containerItem">
<div className="form__containerItemName">
<label>Compose Mail</label>
<button
disabled={loading}
onClick={handleRequest}
type="submit"
className="btn btn-info"
>
Send
</button>
</div>
</div>
<div className="form__containerItem">
<div className="container__composeMail">
<textarea
value={message}
onChange={handleQuillChange}
className="quill"
placeholder="Enter Content from here..."
/>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
);
}
So I am trying to send data that is inputted from a form in React to an e-mail address.
Everything is working perfectly, except where I try and upload a file and it only sends the text of the path file to the e-mail.
eg, the email will look like this:
From: test
Email: testing#gmail.com
Message: testing
File: C:\fakepath\2020-06-10 18-49-37.mp4
I obviously don't want the text to show up on the e-mail, but a file to be uploaded instead.
Any ideas on how to make this work.
I will post heaps of code below for everyone to check out.
Thanks in advance!
Form.jsx
import React from 'react'
import Axios from 'axios'
class Form extends React.Component {
constructor(props) {
super(props);
super(props);
this.state = {
name: '',
email: '',
message: '',
file: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState(
{
[event.target.name]: event.target.value,
[event.target.email]: event.target.value,
[event.target.message]: event.target.value,
[event.target.file]: event.target.file,
}
);
}
this.setState({
[name]: value
})
}
handleSubmit(event) {
console.log(this.state)
event.preventDefault();
const data = {
name: this.state.name,
email: this.state.email,
message: this.state.message,
file: this.state.file,
};
Axios.post("api/v1/sendMail", data)
{
alert("Thank you! We will be in touch shortly!")
}
}
render() {
return (
<React.Fragment>
<div className="formContainer centerImg" id="formScale">
<form onSubmit={this.handleSubmit} method="post">
<div className='contact'>
<h2 className="formTitles">YOUR FULL NAME</h2>
<input
name='name'
value={this.state.name}
onChange={this.handleChange}
required />
<h2 className="formTitles">EMAIL ADDRESS</h2>
<input
name='email'
value={this.state.email}
onChange={this.handleChange}
required />
<h2 className="formTitles">UPLOAD FILE</h2>
<input
type='file'
name='file'
value={this.state.file}
onChange={this.handleChange} />
<div id='messageForm'>
<h2 className="formTitles">MESSAGE</h2>
<textarea
name='message'
value={this.state.message}
onChange={this.handleChange}
required />
</div>
<div id='submit-btn'>
<input type='submit' value='SUBMIT' />
</div>
</div>
</form>
</div>
</React.Fragment>
)
}
}
export default Form
(server) index.js
const server = require('./server')
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json());
server.use(cookieParser());
const { sendEmail } = require("../server/routes/mail");
server.post("/api/v1/sendMail", (req, res) => {
sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
});
const port = 3000
server.listen(port, () => {
// eslint-disable-next-line no-console
console.log('Server listening on port', port)
})
mail.js
const mailer = require("nodemailer");
const getEmailData = (name, email, message, file) => {
let data = null;
data = {
from: "Contact Form",
to: "(*correct e-mail here*)",
subject: `Message from the contact form!`,
html: `<b>From:</b> ${name}
<br><br><b>Email:</b> ${email}
<br><br><b>Message:</b> ${message}
<br><br><b>File:</b> ${file}`
}
return data;
}
const sendEmail = (name, email, message, file) => {
const smtpTransport = mailer.createTransport({
service: "Gmail",
auth: {
user: "(correct e-mail here)",
pass: "(correct password here)"
}
})
const mail = getEmailData(name, email, message, file)
smtpTransport.sendMail(mail, function(error, response) {
if(error) {
console.log(error)
} else {
alert( "Thank you! We will be in touch shortly!")
}
smtpTransport.close();
})
}
module.exports = { sendEmail }
I suggest you send a FormData and parse the FormData on the server.
For express servers you can use multer to parse the request.
send the form data on the client side:
const formData = new FormData();
formData.append("name", this.state.name);
formData.append("email", this.state.email);
formData.append("message", this.state.message);
formData.append("file", this.state.file);
Axios.post("api/v1/sendMail", formData);
on server side, use the directUpload middleware and console.log(req.files) in your request handler:
const upload = multer({
storage: multer.memoryStorage()
});
const directUpload = upload.fields([{
name: "name"
}, {
name: "email"
}, {
name: "message"
}, {
name: "file"
}]);
server.post("/api/v1/sendMail", directUpload, (req, res) => {
console.log(req.files);
sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
});
You can either send FormData or convert file to dataUri and handle it on the backend
Form Data
handleSubmit(event) {
event.preventDefault();
// or you can set ref to form and use new FormData(formRef.current)
// but then keeping state doesnt make sense at all
const formData = new FormData();
for(let [key, value] of Object.entries(this.state)) {
formData.append(key, value);
}
Axios.post("api/v1/sendMail", formData)
{
alert("Thank you! We will be in touch shortly!")
}
}
handleFileChange({target: {name, files}}) {
this.setState(state => ({...state, [name]: files[0]}))
}
<input
type='file'
name='file'
onChange={this.handleFileChange} />
Data Uri
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
handleSubmit(event) {
event.preventDefault();
const data = {...this.state};
Axios.post("api/v1/sendMail", data)
{
alert("Thank you! We will be in touch shortly!")
}
}
handleFileChange({target: {name, files}}) {
toBase64(files[0]).then(dataUri => {
this.setState(state => ({...state, [name]: dataUri}))
})
}
<input
type='file'
name='file'
onChange={this.handleFileChange} />
Also this can be simplified
handleChange({target: {name, value}}) {
this.setState(state => ({...state, [name]: value}))
}
Example
const { Component, Fragment, createRef } = React;
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
class Form extends Component {
constructor(props) {
super(props);
this.state = {
variant1: {
name: '',
email: '',
message: '',
file: null,
},
variant2: {
name: '',
email: '',
message: '',
file: null
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit1 = this.handleSubmit1.bind(this);
this.handleSubmit2 = this.handleSubmit2.bind(this);
this.handleFileChange1 = this.handleFileChange1.bind(this);
this.handleFileChange2 = this.handleFileChange2.bind(this);
this.formRef = createRef(null);
}
handleFileChange1({target: {name, files}}) {
toBase64(files[0]).then(dataUri => {
this.setState(state => ({
...state,
variant1: {
...state.variant1,
[name]: dataUri
}
}))
})
}
handleFileChange2({target: {name, files}}) {
this.setState(state => ({
...state,
variant2: {
...state.variant2,
[name]: files[0]
}
}))
}
handleChange({target: {name, value}}) {
this.setState(state => ({
...state,
variant1: {
...state.variant1,
[name]: value
},
variant2: {
...state.variant2,
[name]: value
}
}))
}
handleSubmit1(event) {
const data = {...this.state.variant1}
console.log('json', data);
}
handleSubmit2(event) {
const formData = new FormData();
for(let [key, value] of Object.entries(this.state.variant2)) {
formData.append(key, value);
}
console.log('form data', [...formData.entries()]);
const formData1 = new FormData(this.formRef.current);
console.log('formdata ref', [...formData1.entries()]);
}
render() {
const { name, email, message } = this.state.variant1;
return (
<Fragment>
<div className="formContainer centerImg" id="formScale">
<form ref={this.formRef} onSubmit={(event) => {event.preventDefault();this.handleSubmit1(event);this.handleSubmit2(event)}} method="post">
<div className='contact'>
<h2 className="formTitles">YOUR FULL NAME</h2>
<input
name='name'
value={name}
onChange={this.handleChange}
required />
<h2 className="formTitles">EMAIL ADDRESS</h2>
<input
name='email'
value={email}
onChange={this.handleChange}
required />
<h2 className="formTitles">UPLOAD FILE</h2>
<input
type='file'
name='file'
onChange={(event) => {this.handleFileChange1(event);this.handleFileChange2(event)}} />
<div id='messageForm'>
<h2 className="formTitles">MESSAGE</h2>
<textarea
name='message'
value={message}
onChange={this.handleChange}
required />
</div>
<div id='submit-btn'>
<input type='submit' value='SUBMIT' />
</div>
</div>
</form>
</div>
</Fragment>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
Józef Podlecki provided guidance to get the right solution, this is the final code to anyone who is trying to get the final solution to work.
Form.jsx
import React from 'react'
import Axios from 'axios'
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
message: '',
file: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleFileChange = this.handleFileChange.bind(this);
}
handleFileChange({target: {name, files}}) {
toBase64(files[0]).then(dataUri => {
this.setState(state => ({...state, [name]: dataUri}))
})
}
handleChange(event) {
this.setState(
{
[event.target.name]: event.target.value,
[event.target.email]: event.target.value,
[event.target.message]: event.target.value,
}
);
}
handleSubmit(event) {
event.preventDefault();
const data = {...this.state};
Axios.post("api/v1/sendMail", data)
{
alert("Thank you! We will be in touch shortly!")
}
}
render() {
return (
<React.Fragment>
<div className="formContainer centerImg" id="formScale">
<form onSubmit={this.handleSubmit} method="post">
<div className='contact'>
<h2 className="formTitles">YOUR FULL NAME</h2>
<input
name='name'
value={this.state.name}
onChange={this.handleChange}
required />
<h2 className="formTitles">EMAIL ADDRESS</h2>
<input
name='email'
value={this.state.email}
onChange={this.handleChange}
required />
<h2 className="formTitles">UPLOAD FILE</h2>
<input
type='file'
name='file'
// value={this.state.file}
onChange={this.handleFileChange} />
<div id='messageForm'>
<h2 className="formTitles">MESSAGE</h2>
<textarea
name='message'
value={this.state.message}
onChange={this.handleChange}
required />
</div>
<div id='submit-btn'>
<input type='submit' value='SUBMIT' />
</div>
</div>
</form>
</div>
</React.Fragment>
)
}
}
export default Form
(server) index.js
const server = require('./server')
const express = require('express')
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
server.use(express.json({limit: '50mb'}))
server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json());
server.use(cookieParser());
const { sendEmail } = require("../server/routes/mail");
server.post("/api/v1/sendMail", (req, res) => {
sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
});
const port = process.env.PORT || 3000;
server.listen(port, () => {
// eslint-disable-next-line no-console
console.log('Server listening on port', port)
})
mail.js
const mailer = require("nodemailer");
const getEmailData = (name, email, message, file) => {
let data = null;
data = {
from: "Contact Form",
to: "(correct e-mail here)",
subject: `Message from the contact form!`,
attachments: [
{
path: `${file}`
}
],
html: `<b>From:</b> ${name}
<br><br><b>Email:</b> ${email}
<br><br><b>Message:</b> ${message}`
}
return data;
}
const sendEmail = (name, email, message, file) => {
const smtpTransport = mailer.createTransport({
service: "Gmail",
auth: {
user: "(correct e-mail here)",
pass: "(correct password here)"
}
})
const mail = getEmailData(name, email, message, file)
smtpTransport.sendMail(mail, function(error, response) {
if(error) {
console.log(error)
} else {
alert( "Thank you! We will be in touch shortly!")
}
smtpTransport.close();
})
}
module.exports = { sendEmail }
React js front end
const AddPost = ({setAlert}) => {
const [post, setPost] = useState({
name: '',
subject: '',
description: '',
categories: '',
errors: {}
});
const [file, setFile] = useState('');
const [category, setCategory] = useState([]);
useEffect(()=>{
axios.get('/api/categories')
.then((res)=>{
setCategory(res.data);
})
.catch(err => console.error(err))
},[]);
const {name, subject, description,categories} = post;
const onChangeHandler = e =>{
setFile(e.target.files[0]);
};
const onChange = e =>{
setPost({...post, [e.target.name]: e.target.value });
};
const onSubmit = e => {
e.preventDefault();
const formData = new FormData();
formData.append('myImage',file);
const config = {
headers:{'Content-Type': 'multipart/form-data'}
};
const data = {
name: name,
subject: subject,
description: description,
categories: categories,
...formData
};
axios.post('/api/articles/add',data,config)
.then( res => {
console.log('success test', res.data);
setAlert('Article Added','success');
})
.catch((err) => {
console.log('error failed',err);
});
setPost({
name: '',
subject: '',
description: '',
categories: '',
});
setFile({file:''})
};
return (
<Fragment>
<div className="container">
<div className="row justify-content-center">
<div className="col-6">
<h3>Add Posts</h3>
<form onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input
type="text"
name='name'
value={name}
className="form-control"
placeholder="Authors name"
onChange={e => onChange(e)}
/>
</div>
<div className="form-group">
<input
type="text"
name='subject'
value={subject}
className="form-control"
placeholder="subject"
onChange={e => onChange(e)}
/>
</div>
<div className="form-group">
<select name='categories'
value={categories}
onChange={e => onChange(e)}
className="form-control">
<option selected>Choose category</option>
{
category.map((item,index)=>(
<option key={index}
>{item.name}
</option>
))
}
</select>
</div>
<div className="form-group">
<textarea
rows="6"
className="form-control"
name='description'
value={description}
placeholder="content"
onChange={e => onChange(e)}> </textarea>
</div>
<input type="file" name='myImage' onChange={e => onChangeHandler(e)} />
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</Fragment>
);
};
This is code for node backend
router.post('/add',(req,res) => {
upload(req,res,(err) => {
if(err){
res.send(err);
}else{
console.log(req.file);
res.send('test');
}
});
var name = req.body.name;
var subject = req.body.subject;
var description = req.body.description;
var categories = req.body.categories;
if(req.file){
var myImage = req.file.filename
}else{
myImage = 'noImage2.jpg'
}
newArticle = new Article({
name: name,
subject: subject,
description: description,
categories: categories,
image: myImage
});
newArticle.save();
try{ res.send('success')}
catch{res.status(400).json('error')}
});`
I have a react blog that contains authors name, title, body and image, I'm using multer in my node server to handle image upload but i don't know how to send both the image and other form data together. I can send them separately. But i need to send them together I've tried formData. Please any help will be appreciated.