I'm using NodeJS/Express and EJS to create a form to an API route. But I'm having a trouble connecting my post route(which contents an id) with the ejs form. How can i add the id to the ejs.
This is my post route
router.post('/:id/new', upload.single('file'), async (req, res) => { //here i'm trying to add project id to the url
//const project = await Project.findById(req.params.id)
const releasenoteData = {
user : await req.user._id,
title: req.body.title,
path: req.file.path,
originalName: req.file.originalname,
description: req.body.description,
createdAt: req.body.createdAt,
}
try {
const releasenote = await ReleaseNote.create(releasenoteData)
console.log(releasenote)
res.redirect('/')
} catch {
if (releasenoteData.path != null) {
res.redirect('/new', {
errorMessage: 'Error Creating the Release Note'
})
}
}
})
Now I want to connect the above post route with a ejs form and get the relevant data from it. How can I do that with the project id in the route.
<form action="/new" method="POST" enctype="multipart/form-data"> //here before new id should be added i think
<label for="text">Title: </label>
<input type="text" id="title" name="title">
<br><br>
<label for="file">File: </label>
<input type="file" id="file" name="file" required>
<br><br>
<label for="text">Description: </label>
<input type="text" id="description" name="description">
<br><br>
<label for="date">Upload Date: </label>
<input type="date" id="createdAt" name="createdAt">
<br><br>
<button type="submit">Add Release Note</button>
</form>
The answer, confirmed by the OP as a working solution, is to drop the action part of the form. This makes the form POST to its default location
As per the spec:
[...]
Let action be the submitter element's action.
If action is the empty string, let action be the URL of the form document.
This means that if the form is first GET, action can be omitted and the url is preserved (actually this is handy if the url contains multiple parameters).
Related
I have been trying to create a simple web app where you can post images and a little description. It is for an Instagram Clone project. I am using multer and express on the backend to parse the body and the file, and it works perfectly fine. The problem is on the frontend. I provide a form where you put name, description and the image to upload, then with the Fetch API I send the body to my api on the backend.
I noticed that the page reloads every time I submit the form despite the use of event.preventDefault() and event.stopPropagation() for the form sumbit event.
In addition, I have realised that it does so only when also uploading the file, in fact, if I leave the name and description alone, it doesn't reload the page, whereas if I live the file upload in there it just reloads it.
Is this a bug of the fetch API or am I not considering something?
Here's the code on the frontend that handles the fetch request to my api:
const instaForm = document.getElementById("post-pic");
instaForm.addEventListener("submit", (event) => {
event.preventDefault();
event.stopPropagation();
let instaFormData = new FormData(instaForm);
let url = `${baseUrl}/create-insta`;
fetch(url, {
method: "POST",
body: instaFormData,
})
.then((data) => data.json())
.then((response) => {
instaForm.reset();
console.log(response);
})
.catch((err) => console.error(err));
});
Consider that if I leave the input for the file blank, the page doesn't reload so it is definitely a problem with the file upload.
For now, for debugging my API is sending back a simple "Received" response and nothing else.
HTML Form
<form method="POST" id="post-pic" enctype="multipart/form-data">
<input
type="text"
id="name"
name="name"
placeholder="Enter a name..."
/>
<textarea
name="description"
id="description"
rows="10"
placeholder="A short description..."
></textarea>
<input type="file" id="picture" name="insta" />
<button id="publish" type="submit">Publish</button>
</form>
You should catch the event when clicking on the form button.
Try this:
<form method="POST" id="post-pic" enctype="multipart/form-data">
<input
type="text"
id="name"
name="name"
placeholder="Enter a name..."
/>
<textarea
name="description"
id="description"
rows="10"
placeholder="A short description..."
></textarea>
<input type="file" id="picture" name="insta" />
<button id="publish" type="button">Publish</button>
</form>
JS Script:
const instaForm = document.getElementById("post-pic");
const buttonForm = document.getElementById("publish");
buttonForm.addEventListener("click",(event) => {
event.preventDefault();
let instaFormData = new FormData(instaForm);
let url = `${baseUrl}/create-insta`;
fetch(url, {
method: "POST",
body: instaFormData,
})
.then((data) => data.json())
.then((response) => {
instaForm.reset();
console.log(response);
})
.catch((err) => console.error(err));
});
}
I hope it could help you.
Regards.
i have a project where I have a form where you can fill in a first- and last-name, and then the names will be uploaded to my MongoDB database, and then placed on another page in p-tags.
I have succeeded to get this done, however the problem is that I need a payment to be succeeded before the form data will be uploaded to my database.
Currently I have both the forms and javascript for the submit-form and the stripe-payment api.
First, I have the script for the stripe API, and I have the script for both saving and posting form data to/from db:
// routes
app.get('/', (req, res) => {
res.render('index', {
stripePublishableKey: 'pk_test_51IVfPNLNmuMLNSTmFh4R5GIZMjnTTf4mQGy5UQRTam6vfooJWhyXIrT5tIclvgydZm1EYPfN1VgBBCZAN6Las1Ap007qYaR6zr'
});
});
// charge route
app.post('/charge', (req,res)=>{
const amount = 2500;
stripe.customers.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer => stripe.charges.create({
amount,
description: 'coviDON',
currency: 'usd',
customer: customer.id
}))
.then(charge => res.render('success'));
});
// the page where the form data will be submitted
app.get('/wall', (req, res) => {
Covid.find().sort({ createdAt: -1 })
.then((result)=>{
res.render('wall', {covids: result})
})
.catch((err)=>{
console.log(err);
})
});
// save form data to db and post to wallsite
app.post('/wall', (req, res) => {
const covid = new Covid(req.body);
covid.save()
.then((result)=>{
res.redirect('/wall');
})
.catch((err)=>{
console.log(err);
})
});
Then, I have the index page where the two forms are placed:
<body>
<div class="create-attribute">
<form action="/wall" method="POST">
<label for="first-name">First name</label>
<input type="text" id="firstName" name="firstName" required>
<br><br>
<label for="last-name">Last name</label>
<input type="text" id="lastName" name="lastName" required>
<button>Buy</button>
</form>
</div>
<form action="/charge" method="POST">
<script
src="https://checkout.stripe.com/checkout.js"
class="stripe-button"
data-key= "<%= stripePublishableKey %>"
data-amount="2500"
data-name="Web Development Ebook"
data-description="Ebook written by Brad Traversy"
data-image="/img/marketplace.png"
data-locale="auto"
>
</script>
<script>
// hide default stripe button
document.getElementsByClassName('stripe-button-el')[0].style.display = 'none';
</script>
<button type="submit" class="btn btn-outline-dark text-white btn-lg">Purchase for 25$</button>
</form>
</body>
So, my goal and question is how I can connect these two together, so I have to press the stripe-button and pay the fee. After the payment is succeeded I want the submit-form to be processed so the data the user inputs will be stores to the db, and then posted to the wall-site in the p-tags??
First of all, it looks like you're using Legacy Checkout, which has been deprecated for years. It is recommended that you not integrate this way, and instead prefer the new Checkout. If this is an existing integration, you should consider migrating.
That said, if you want to do something like this you'll want to switch to the custom configuration and leverage the token/source function callbacks.
I am newbie to nodejs. Facing problem in posting data throug html forms....
In my server.js i have added this post function request
app.get('/',(req,res)=>{
res.end(`
<!doctype html>
<html>
<body>
<form action="/product" method="post" role="form" enctype="multipart/form-data">
<input type="text" id="title" name="title" placeholder="title">
<input type="number" name="price" placeholder="price">
<input type="text" name="description" placeholder="description">
<input type="text" name="category" placeholder="category" >
<input type="file" name="product" >
<button>Save</button>
</form>
</body>
</html>
`);
})
Post function decleration in product.js
const productRouter = express.Router();
productRouter.use(bodyParser.json());
productRouter.route('/')
.get((req,res,next)=>{
Product.find({})
.then((products)=>{
res.statusCode=200;
res.setHeader('Content-Type','application/json');
res.json(products);
},(err)=>next(err))
.catch((err) => next (err));
})
.post((req,res,next)=>{
console.log(req.body);
var Prod= new Product({
title:req.body.title,
price:req.body.price ,
description: req.body.description,
category:req.body.category,
img: req.body.img
});
Prod.save()
.then((product)=>{
console.log('product added ',product );
res.statusCode=200;
res.setHeader('Content-Type','application/json');
res.json(product);
},(err)=> next(err))
.catch((err) => next(err));
})
Post request in working fine when i am doing it using POSTMAN , but when try to do using html form i am facing the follwing error:
ValidationError: Product validation failed: title: Path title is required., price: Path price is required., description: Path description is required., category: Path category is required., img: Path img is required.
at model.Document.invalidate (C:\Users\mayank\Desktop\cata\node_modules\mongoose\lib\document.js:2598:32)
Check the notes from body-parser README section (attached screenshot for reference). BodyParser doesn't support the multipart styles due to their complexity. Instead, listed some nm-modules to use.
I suggest MULTER or MILTIPARTY
Here's a reference of the code that's working.I have sent the received-payload as JSON response. You could go ahead and process the way, you intend.
router.post('/ola', (req, res) => {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
res.json({ fields: fields, files: files });
});
})
as the title says, I want to submit a form and update the values from the form (Mysql result) without refreshing the whole page.
See Image 1, I want if I press the blue button that the values updated.
Can someone help me?
Thanks.
If you are willing to use newer apis like Promise and fetch, it's super easy and neat.
foo.submit.addEventListener("click", (e) => {
e.preventDefault();
fetch("YOUR_URL", {
method: 'POST',
body: new URLSearchParams({
name: foo.user_name_value,
email: foo.user_mail.value
})
}).then(response => {
return response.json() // assume returning data is in json format, otherwise .text() could be used
}).then(data => {
// deal with return data
}).catch(err => {
// deals with errors
})
})
<form name="foo">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="user_name">
</div>
<div>
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_mail">
</div>
<div>
<button name="submit" type="submit">Send your message</button>
</div>
</form>
Older method XHR shares same idea, but requires a bit more code. You may use axios or so to simplify the process.
I am attempting to set up user login and role authentication with Vue, without using Vuex, as it's a bit much for the scope of our application. After a failed initial attempt to use jQuery AJAX outside of Vue, I resigned myself to making it work with Vue's data-oriented model, which I've been struggling with (I'm a designer by trade, not really a developer). My backend developer is writing in plain PHP and using mySQL, for reference.
Taking inspiration from this tutorial, I am trying to use v-model to send the form data to the server via axios.
Template:
<form class="login-form" id="loginform" #submit.prevent="login">
<div class="form-group space">
<label class="float-label" for="username">Username</label>
<input v-model="username" type="username" id="username" class="form-control" placeholder="username">
</div>
<div class="form-group">
<label class="float-label" for="username">Password</label>
<input v-model="password" type="password" id="password" class="form-control" placeholder="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary float-right" id="login">Log in</button>
</div>
</form>
Script:
export default {
name: 'Login',
data () {
return {
username: '',
password: ''
}
},
methods: {
login: function () {
const loginInfo = { username, password }
console.log(loginInfo)
new Promise ((resolve, reject) => {
axios({url: 'api.com/index.php', data: loginInfo, method: 'POST' })
.then(resp => {
const token = resp.data.token
localStorage.setItem('user_token', token) // store the token in localstorage
const employeeId = resp.data.employee_id
localStorage.setItem('employee_id', employeeId) // store the id in localstorage
resolve(resp)
console.log(resp);
})
.catch(err => {
localStorage.removeItem('user_token') // if the request fails, remove any possible user token if possible
reject(err)
})
})
// myLoginRoutine(loginInfo).then(() => {
// this.$router.push('/')
// })
}
}
}
The request was going through no problem, but wasn't returning anything! I decided to check and see what I was sending him... and lo and behold, const loginInfo was not the input value, as expected, but {username: input#username.form-control, password: input#password.form-control}
I am, quite frankly, very confused. I've used v-model previously on form inputs with no issues, and have no clue why this is happening or how to fix it. Any thoughts?
For future visitors: The axios data expects an object with those keys for the backend, but you don't fill the object properly.
Change
const loginInfo = { username, password }
to
const loginInfo = { username: this.username, password: this.password }