I'm trying to create a simple form which can upload file(pdf & image) and texts together using Node.js. Nonetheless, I don't wanna save the pdf file to MySql database, rather I want it to be kept in my internal storage "./uploads" folder. I have used npm formidable, mv, and multer, yet nothing works, anybody knows why?
Here's my html form
<form action="/auth/registerEvent" method = "POST">
<h5> Enter Your Event Information</h5>
<div class="form-group">
<label for="eventName">Event Name</label>
<input type="text" class="form-control" id="eventName" name="eventName" placeholder="Event Name">
</div>
<div class="form-group">
<label for="eventDescription">Description</label>
<textarea class="form-control" id="eventDescription" name="eventDescription" placeholder="Event Description: No more than 200 words" rows="3"></textarea>
</div>
<div class="form-group">
<label for="eventPoster">Poster</label>
<input type="file" class="form-control" id="eventPoster" name="eventPoster" enctype="multipart/form-data" accept=".jpg, .png, .jpeg">
</div>
<div class="form-group">
<label for="eventProposal">Sponsor Proposal</label>
<input type="file" class="form-control" id="eventProposal" name="eventProposal" enctype="multipart/form-data" accept=".pdf">
</div>
<br>
<button type="submit">Submit</button>
</form>
This is my app.js
const express = require('express');
const path = require('path');
const app = express();
const mysql = require('mysql');
const dotenv = require('dotenv');
dotenv.config({path: './.env'}); // connect to .env
// set views folder
app.set('view engine', 'html');
app.engine('html', require('hbs').__express);
// set the directory to css and js
const publicDirectory = path.join(__dirname, './public');
app.use(express.static(publicDirectory));
// Parse URL encoded bodies (as sent by HTML Form)
app.use(express.urlencoded({extended: false}));
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
// Define routes
app.use('/', require('./router/pages.js'));
app.use('/auth', require('./router/auth.js'));
// connect to mysql
const db = mysql.createConnection({
host: process.env.LOCALHOST,
user: process.env.USER,
password: process.env.PASSWORD,
database: process.env.DATABASE,
});
db.connect( (err) => {
if (err) console.log(err);
else console.log('Database is connected');
} )
// laptop server
app.listen(3000, (req, res)=>{
console.log('Server is running at localhost:3000');
});
and finally the "auth.js"
const formidable = require('formidable');
const fs = require('fs');
const mysql = require('mysql');
const db = mysql.createConnection({
host: process.env.LOCALHOST,
user: process.env.USER,
password: process.env.PASSWORD,
database: process.env.DATABASE,
});
exports.registerEvent = (req, res) => {
const {
eventName, eventInstitution,
// eventStartDate, eventEndDate,
eventAddress, eventDescription,
eventPoster, eventProposal,
// eoName, eoPhone, eoEmail
} = req.body;
if (req.url === "/registerEvent") {
const form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
const oldPath = eventPoster.path;
const newPath = './uploads' + eventPoster;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err;
});
})
}
// db start
db.query('INSERT INTO registerevent SET ? ', {
EventName: eventName,
Institution: eventInstitution,
// StartDate: eventStartDate,
// EndDate: eventEndDate,
Address: eventAddress,
Description: eventDescription,
// Poster: eventPoster,
// Proposal: eventProposal,
// ContactName: eoName,
// PhoneNumber: eoPhone,
// Email: eoEmail,
}, (error, result) => {
if (error) { console.log(error); }
else {
res.statusCode = 302;
res.setHeader("Location", "/feedback");
res.end();
}
});
// db end
}
So when the customer enters the name & address it goes to sql, and the poster and proposal files will be sent to my "/uploads" directory. Please help
Related
This question already has an answer here:
ExpressJS request body is empty if i don't use multer
(1 answer)
Closed 7 months ago.
I have a form with two numeric input fields that I'd like to send to the backend, but req.body is always empty. Here is my form:
<form
class="mt-3"
id="myForm"
enctype="multipart/form-data"
action="/submit-thing1and2"
>
<div class="mb-2">
<label for="thing1" class="form-label"
>Thing 1</label
>
<input
type="number"
class="form-control"
id="thing1"
name="thing1"
required
/>
</div>
<div class="mb-2">
<label for="thing2" class="form-label"
>Thing 2</label
>
<input
type="number"
class="form-control"
id="thing2"
name="thing2"
required
/>
</div>
<div class="form-group-row mb-3">
<button id="submitThings" type="submit" class="btn btn-primary">
Submit Things
</button>
</div>
</form>
I have tried using enctype="application/json", "text/html", and "application/x-www-form-urlencoded", and all of them still return an empty object in req.body.
Here is my post request:
form = document.getElementById("myForm");
form.addEventListener("submit", async (event, arg) => {
event.preventDefault();
console.log(event.target.action);
console.log(event.target);
let data = new FormData(event.target);
console.log(data.toString());
fetch(event.target.action, {
method: "post",
body: new FormData(event.target),
})
.then((res) => {
console.log(res.status);
return res.text();
})
.then((data) => {
console.log(data);
});
});
And here is my server-side handling of the post request - the console.log works, just shows an empty object:
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || 5000;
const app = express();
app.use(express.static(path.join(__dirname)));
app.use(express.json());
app.use(
express.urlencoded({
extended: true,
})
);
app.post("/submit-thing1and2", async (req, res) => {
console.log("req.body", req.body);
res.send(req.body);
});
app.get("/", (req, res) => {
res.sendFile("./html/index.html", { root: __dirname });
});
app.listen(PORT, () => console.log(`Listening on ${PORT}`));
Use multer to parse multipart/form-data requests:
app.post("/submit-thing1and2",
multer().fields([{name: "thing1"}, {name: "thing2"}]),
async function(req, res) {
...
});
On my home page I have a button "register" with an onclick event. When clicked a hidden div on that same home page is given "style.display = 'block';" with javascript revealing my registration form. The form takes a username, email, and a password, and when submitted a new user is created and added to my mongoDB database. Then the user gets send to the home page again (same place as they already were, but this makes the div hidden again) Everything works as expected, except for error handling...
Inside my Schema for a new user, I have set it so the username must be unique. This means that when I try to register an account with a username that is already taken, I get an error, meaning the "catch" part of my code is executed. My problem is that I dont know what to type in here to send the user back to the home page with the register form opened and the previously filled in information there along with an error message saying that the username is taken. Is there a way to cancel the form post request and just return back to the previous page? or do I need to structure my code completely differently?
Bonus question: the register button will be available on all my views like on about.html or products.html, how do I redirect the user back to the page he was on when he submitted the form, because now it allways takes you to the index.html
Router:
const router = require("express").Router();
const User = require("../models/User");
const CryptoJS = require("crypto-js");
const jwt = require("jsonwebtoken");
// Register account
router.post("/register", async (req, res) => {
const newUser = new User({
username: req.body.username,
email: req.body.email,
password: CryptoJS.AES.encrypt(req.body.password, process.env.CRYPTO_PASS_SEC).toString()
});
try {
const savedUser = await newUser.save();
res.redirect("../");
} catch (err) {
console.log(err);
console.log("an error occured when registering");
res.redirect(400, "../");
}
});
module.exports = router;
Schema:
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
username: {type: String, required: true, unique: true},
email: {type: String, required: true, unique: true},
password: {type: String, required: true},
isAdmin: {type: Boolean, default: false}
}, {timestamps: true});
module.exports = mongoose.model("User", UserSchema);
html for form:
<div id="dialogRegister" class="dialog"> <!-- Set to display: none; as default -->
<div id="dialogContent">
<div id="btnCloseRegister" class="btnClose">X</div>
<p class="dialogHeader">Create An Account</p>
<form action="/auth/register" method="post">
<div class="formGroup">
<label for="username">Username:</label>
<input type="text" name="username" required>
</div>
<div class="formGroup">
<label for="email">Email:</label>
<input type="email" name="email" required>
</div>
<div class="formGroup">
<label for="password">Password:</label>
<input type="password" name="password" required>
</div>
<div class="btnGroup">
<button type="submit" id="btnRegister" class="btnAuth">Register</button>
<button type="button" id="btnCancelRegister" class="btnCancel">Cancel</button>
</div>
</form>
</div>
</div>
server:
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
dotenv.config();
const path = require("path");
const methodOverride = require("method-override");
const productsRouter = require("./routes/products");
const authRouter = require("./routes/auth");
mongoose.connect(process.env.MONGO_URL)
.then(() => console.log("Successfully connected to database"))
.catch((err) => console.error(err))
app.set("view engine", "ejs");
app.use('/', express.static(path.join(__dirname, '/public')));
app.use(methodOverride('_method'));
app.use(express.urlencoded({ extended: false }));
app.get("/", (req, res) => {
res.render("home/index");
})
app.use("/products", productsRouter);
app.use("/auth", authRouter);
app.listen(5000);
Javascript:
var btnOpenRegister = document.getElementById("btnOpenRegister");
var btnCloseRegister = document.getElementById("btnCloseRegister");
var btnCancelRegister = document.getElementById("btnCancelRegister");
var btnRegister = document.getElementById("btnRegister");
var dialogRegister = document.getElementById("dialogRegister");
btnOpenRegister.onclick = () => {
dialogRegister.style.display = "block";
}
btnCancelRegister.onclick = () => {
dialogRegister.style.display = "none";
}
btnCloseRegister.onclick = () => {
dialogRegister.style.display = "none";
}
dialogRegister.addEventListener("click", (e) => {
if (e.target === dialogRegister) {
dialogRegister.style.display = "none";
};
});
I'm trying to add a contact form in my website using nodemailer.
With plain-text, the email was sent (with the cmd node server.js), but since I have added a form in my html and tried to send the "req.bodies" using a route, it doesn't work anymore and I have the following error : Error: Missing credentials for "PLAIN".
Here are my codes :
Index.js
var express = require("express");
var router = express.Router();
const nodemailer = require("nodemailer");
/* GET home page. */
router.get("/", function (req, res, next) {
res.render("index", { title: "Express" });
});
router.post("/send-email", async function (req, res, next) {
"use strict";
var email = req.body.email;
var name = req.body.name;
var message = req.body.message;
var transporter = nodemailer.createTransport({
// host: "smtp.gmail.com",
service: "gmail",
// secure : false,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
console.log("message :", req.body.message, "email :", req.body.email);
// send mail with defined transport object
var mailOptions = {
from: email,
to: process.env.EMAIL,
subject: "Nouveau mail contact de " + name, // Subject line
text: name + "0102030405" + message,
};
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
res.redirect("/");
}
});
});
module.exports = router;
Server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const port = 3000;
require("dotenv").config();
app.use(bodyParser.json());
const nodemailer = require("nodemailer");
app.listen(port, () => {
console.log(`Server running on ${port}`);
});
app.use("/index", require("./routes/index"));
// let transport = nodemailer.createTransport({
// service: "gmail",
// auth: {
// user: process.env.EMAIL,
// pass: process.env.PASSWORD,
// },
// });
// let mailOptions = {
// from: '"Fred Foo đź‘»" <process.env.EMAIL>', // sender address
// to: "process.env.EMAIL", // list of receivers
// subject: "Hello âś”", // Subject line
// text: "Hello world?", // plain text body
// html: "<b>Hello world?</b>", // html body
// };
// transport.sendMail(mailOptions, function (err, data) {
// if (err) {
// console.log("Error Occurs");
// } else {
// console.log("Email sent !!");
// }
// });
html
<form action="/send-email" method="POST">
Your Name:
<input type="text" name="name">
Email Address:
<input type="email" name="email" placeholder="Email">
Message:
<textarea name="message"></textarea>
<input type="submit" value="Submit">
</form>
Body-Parser doesn't seem to work because it is strikeout.
“less secure” apps is enabled on my gmail account
Thank you very much for your help !
EDIT : I think it's because it doesn't recognize my process.env because when I directly write them, it works.
I put my file .env in the same directory but it still does not recognize them.
I'm using Node.Js and express framework for my application.
I build HTML forms and upon submitting I'm not able to receive my form data on API request.
My HTML:
<form method="post" action="/create">
<input type="text" name="user.name" />
<input type="text" name="user.email" />
<input type="text" name="user.address.city" />
<input type="text" name="user.address.land" />
<input type="submit" value="Submit">
</form>
JSON object should been obtained at my API:
{
"user": {
"name": "toto",
"email": "toto#mail.com",
"address": {
"city": "yyyyy",
"land": "zzzz"
}
}
}
How to do this with Node.js, Express 4 and is there another library for this?
You can prepare your own middleware that parses the incoming form data using body-parser's urlencoded() and turns it into a structured JSON:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
function setDeepValue(path, obj, value) {
const tokens = path.split('.');
const last = tokens.pop();
for (const token of tokens) {
if (!obj.hasOwnProperty(token)) {
obj[token] = {};
}
obj = obj[token];
}
obj[last] = value;
}
app.use(bodyParser.urlencoded(), function(req, res, next) {
let obj = {};
for (const key in req.body) {
setDeepValue(key, obj, req.body[key]);
}
req.body = obj;
next();
});
app.post('/create', function(req, res) {
console.log(req.body)
})
In your HTML code you are posting to a create route.
So in express you need to create that route
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.post('/create', function(req, res) {
console.log('----- MY BODY -----')
console.log(req.body)
// do something more clever
res.send('We posted to this route')
})
First we require express, then we require body-parser and finally initialize our express app.
We then use the json middlewere of body-parser to parse the body so that we can easily access it in our handler.
We then define a route to '/create' that accepts posts request (remember that your form is posting to this location).
All that our handler does is to console.log the body of the request, and then shows the message We posted to this route
Follow this guide repository specially created to guide freshers nodejs-frontend-sample-for-freshers
EDIT:
You can use Ajax call to submit form this will also help in Single Page Application
Client-side JS:
function submit() {
// JavaScript uses `id` to fetch value
let email = $("#email").val(),
name = $("#name").val(),
city = $("#city").val(),
land = $("#land").val();
// Can validate each field here and show error like:
if ( validateEmail(email) ) {
$("#emailError").addClass("hide");
} else {
$("#emailError").removeClass("hide");
return;
}
// form request data, doing this will get you data in correct form at NodeJs API
let data = {
user: {
email,
name,
address: {
city,
land
}
}
};
$.ajax({
"url": "/create",
"method": "POST",
"data": data
})
.then( result => {
// On success empty all the input fields.
$("#email").val('');
$("#name").val('');
$("#city").val('');
$("#land").val('');
// Message to notify success submition
alert("Successfully added user.");
return;
})
.catch( err => {
// Notify in case some error occured
alert("An error occured.");
return;
});
}
// Validate Email based upon pattern
function validateEmail (email) {
if ( email && email.match(/^([A-z0-9_.]{2,})([#]{1})([A-z]{1,})([.]{1})([A-z.]{1,})*$/) ) {
return true;
}
return false;
}
HTML:
<form>
<input type="text" id="name" />
<input type="text" id="email" />
<span id="emailError" class="hide error">Valid Email Required</span>
<input type="text" id="city" />
<input type="text" id="land" />
<p onclick="submit()">Submit</p>
</form>
Would recommend you to use cors.js too like:
const cors = require('cors');
// Cross-Origin Resource Sharing
app.use(cors());
You can get object in two ways:
1: Using no extra module something like this
app.post('/create', function (request, response, next) {
let body = [];
request.on('error', (err) => {
console.error(err);
}).on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
console.log(body); // Your object
request.body = body; // Store object in request again
next();
});
}, (req, res) => {
console.log(req.body); // This will have your object
});
Using body-parser with express:
```
// configure the app to use bodyParser() to extract body from request.
// parse urlencoded types to JSON
app.use(bodyParser.urlencoded({
extended: true
}));
// parse various different custom JSON types as JSON
app.use(bodyParser.json({ type: 'application/*+json' }));
// parse some custom thing into a Buffer
app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }));
// parse an HTML body into a string
app.use(bodyParser.text({ type: 'text/html' }));
app.post('/create', function (request, response, next) {
console.log(request.body); // `body-parser did what I did earlier`
});
```
I have some problems to get a login for my webpage.
I have a user in my DB with email: peru#hotmail.com and pass 123.
the problem is that when I make the POST method it returns me the next error:
*Cannot POST /login*
this is my app.js:
var mongoose = require('mongoose');
var express = require('express');
var app=express();
var bodyParser = require('body-parser');
mongoose.connect("mongodb://localhost/myDB");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
var userSchema = {
email:String,
pass:String
};
var Usuario = mongoose.model("Usuario",userSchema);
app.use(express.static("public"));
app.get("/",function(solicitud,respuesta){
respuesta.sendFile('.../prueba.html');
});
app.post("/login",function(require,respuesta){
var email = require.body.email;
var pass = require.body.pass;
console.log("post received: %s %s", email, pass);
User.findOne({email: email, pass: pass}, function(err,user){
if(err){
console.log(err);
}
respuesta.sendFile('.../work.html');
});
});
app.listen(3000);
and now this is my prueba.html:
<html>
<head>
<title></title>
</head>
<body>
<!--div class="col-md-5 center-block no float top-pace text-left"-->
<form method="post" action="/login" >
<input type="text" name="email">
<input type="text" name="pass" >
<button type="submit" >login </button>
</form>
</body>
</html>
You created model as Usuario and using User in your POST request, try changing it to Usuario, as follows:
app.post("/login",function(require,respuesta){
var email = require.body.email;
var pass = require.body.pass;
console.log("post received: %s %s", email, pass);
Usuario.findOne({email: email, pass: pass}, function(err,user){
if(err){
console.log(err);
}
respuesta.sendFile('.../work.html');
});
});