this is my post request to save to mongdb database
router.post("/create", async (req, res) => {
const createJottings = new Jottings({
title: req.body.title,
jottings: req.body.jottings
});
try {
await createJottings.save();
res.json(createJottings);
} catch (err) {
res.json({ message: err });
}
});
it works fine on postman but now i am trying to render it using handlebars to the client. this is the form for the client side using handlebars
<div class="card card-body">
<h3>
Edit Jottings/Idea
</h3>
<form action="/jottings/create" method="get">
<div class="form-group">
<label for="title">
Title
</label>
<input type="text" name="title" class="form-control" required />
</div>
<div class="form-group">
<label for="title">
Jottings
</label>
<textarea name="Description" class="form-control" required></textarea>
</div>
<button type="submit" class="btn btn-primary">
Submit
</button>
</form>
</div>
the form actually loads but when i press submit it doesnt save to mongodb server
{{#each getJottings}}
<div class="card card-body mb-2">
<h4>
{{title}}
</h4>
<p>
{{jottings}}
</p>
<a href="/jottings/edit/{{id}}" class="btn btn-dark btn-block">
Edit
</a>
</div>
{{else}}
<p>
No Ideas and Jottings listed
</p>
{{/each}}
code that outlists saved data in the database if i create it using postman it works but with the form it doesnt.
overview of my jottings route
// Require Mongoose
const router = require("express").Router();
// Setup Models for Jotting
const Jottings = require("../models/jottings.model");
// Setting Endpoints For Routes
// Get All Jottings
router.get("/", async (req, res) => {
try {
const getJottings = await Jottings.find({}).sort({ date: "desc" });
res.render("jottings/index", {
getJottings: getJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Getting routes to set form
router.get("/add", (req, res) => {
res.render("jottings/add");
});
// Get Specific Jottings
router.get("/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
await Jottings.findById(id, (err, jottings) => {
if (!id) {
res.json({ message: err });
} else {
res.json(jottings);
}
});
} catch (err) {
res.json({ message: err });
}
});
// Post to create New Jottings for form
router.post("/create", async (req, res) => {
const createJottings = new Jottings({
title: req.body.title,
jottings: req.body.jottings
});
try {
await createJottings.save();
res.json(createJottings);
} catch (err) {
res.json({ message: err });
}
});
router.get("/edit/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const editJottings = await Jottings.findOne({ _id: id });
res.render("jottings/edit", {
editJottings: editJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Patch to Edit Jottings for form
router.patch("/edit/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const editJottings = await Jottings.updateOne(
{ _id: id },
{ $set: { jottings: req.body.jottings } }
);
res.render("jottings/edit", {
editJottings: editJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Delete to delete Jottings for form
router.delete("/delete/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const deleteJottings = await Jottings.deleteOne({ _id: id });
res.json(deleteJottings);
} catch (err) {
res.json({ message: err });
}
});
// Exporting router
module.exports = router;
i would like the details to be saved to the database when i click the submit button and also redirect me to a list of my saved details.
You form uses method GET while you defined router.post to handle form submission.
Related
So I'm building a MERN app that is supposed to be authenticating using passport. I've created a login page, a register page and a upload route on the frontend, along with a backend server in node js, mongo db and react. I'm using the passport, passport-local, and passport-local-mongoose npm packages to help with session based authentication.
So when I login using my login page, my server does return the success message and I am redirected correctly. When I try to upload, it turns out that the request can't get past my isLoggedIn middleware. But when I try the same with hoppscotch(which runs using the hoppscotch browser extenxsion), it logs in, and both, the upload requests from my upload page and the upload requests from hoppscotch succeed easily and everything works correctly.
Ohkay so here's my code for my login page:
import axios from "axios";
import React, { useState } from "react";
import "./login.css";
const Login = (props) => {
const [username, setUsername] = useState();
const [password, setPassword] = useState();
const onSubmit = (e) => {
e.preventDefault();
const obj = { username: username, password: password };
axios
.post("http://localhost:4000/api/login", obj)
.then((res) => {
console.log("login response: ", res);
if(res.status === 200) {
alert("Logged in!!!");
// window.location.href = "/";
}
})
.catch((e) => {
alert("error");
console.log(e);
});
};
return (
<div className="cont">
<form className="input" onSubmit={onSubmit}>
<label className="label" htmlFor="username">Username:</label>
<input
className="input"
type="text"
id="username"
onChange={(e) => setUsername(e.target.value)}
/>
<label className="label" htmlFor="password">Password:</label>
<input
className="input"
type="password"
id="password"
onChange={(e) => setPassword(e.target.value)}
/>
<button className="button" type="submit" value="submit">
Submit
</button>
</form>
</div>
);
};
export default Login;
And this would be my upload page:
import React, { useState } from "react";
import axios from "axios";
const Home = () => {
const [file, setFile] = useState();
const onSubmit = (e) => {
e.preventDefault();
const data = new FormData();
data.append("file", file);
axios
.post("http://localhost:4000/api/upload/resume", data, {
withCredentials: true,
headers: { "Content-Type": "multipart/form-data" },
})
.then((file) => {
console.log("worked ", file);
})
.catch((e) => {
console.log(e);
});
};
// post to http://localhost:4000/home
return (
<form onSubmit={onSubmit}>
<p>Submit your resume pdf here ( Resume pdf should be 12 Mb or less )</p>
<input
type="file"
id="pdf-file"
onChange={(e) => setFile(e.target.files[0])}
/>
<button type="submit">Upload</button>
</form>
);
};
export default Home;
this is my login route:
router.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) throw err;
if (!user) res.send("No User Exists");
else {
req.logIn(user, (err) => {
if (err) throw err;
res.send("Successfully Authenticated");
console.log(req.user);
});
}
})(req, res, next);
});
And finally this is my isLoggedIn Middleware:
const isLoggedIn = (req, res, next) => {
console.log(req);
if (req.isAuthenticated()) {
console.log("authenticated");
return next();
}
console.log("not authenticated");
throw new Error("User not authenticated");
};
module.exports = isLoggedIn;
I have my update button that performs a get request to fetch the data with the id and fills the slots. Then, using the form below I perform another get request to send a request to update the data.
<form action="//updateBookRequest" method="GET" id="update-book">
<!-- Book Name -->
<div class="form-group">
<label for="name">Name</label>
<input type="hidden" name="id" value="<%= book._id %> ">
<input type="text" name="name" value="<%= book.name %> " placeholder="The Alchemist">
</div>
<!-- Author Name -->
<div class="form-group">
<label for="author">Author</label>
<input type="text" name="author" value="<%= book.author %> " placeholder="Paulo Coelho">
</div>
<!-- Language -->
<div class="form-group">
<label for="language">Language</label>
<input type="text" name="language" value="<%= book.language %> " placeholder="English">
</div>
<!-- Date -->
<div class="form-group">
<label for="date">Date</label>
<input type="date" name="date" value="<%= book.date %> " placeholder="">
</div>
<div class="form-group">
<div class="buttons">
<button class="btn">Cancel</button>
<button class="btn" type="submit">Save</button>
</div>
</div>
</form>
The route looks like this:
route.get('/update-book', services.updateBook)
And the services.updateBook looks like this:
exports.updateBook = (req, res) => {
axios.put(`http://localhost:5000/api/books/${req.query.id}`)
.then(function(response) {
res.redirect('/')
})
.catch(err => {
res.send(err)
})
}
But for some reason, it doesn't update the data.
When I do it in the postman, using the same 'http://localhost:5000/api/books/id', it works just fine and update the data with the postman body as it should.
But, it doesn't when I try to do it in the ejs file with the following section.
I can't seem to find where the problem is. Other functionalities such as adding new data, deleting the data using the id, displaying all the data seem to work fine.
How can I make it to update the data?
This is server.js file:
const express = require('express')
const dotenv = require('dotenv')
const bodyparser = require('body-parser')
const path = require('path')
const connnectDB = require('./server/database/connection')
const app = express()
dotenv.config({path:'config.env'})
const port = process.env.port || 5050
connnectDB()
app.use(bodyparser.urlencoded({extended:true}))
app.set('view engine', 'ejs')
app.use('/css', express.static(path.resolve(__dirname, 'assets/css')))
app.use('/js', express.static(path.resolve(__dirname, 'assets/js')))
app.use('/', require('./server/routes/router'))
app.listen(port, () => {
console.log(`http://localhost:${port}`)
})
This is the server/controller/controller.js
const Userdb = require('../model/model')
exports.create = (req, res) => {
if (!req.body) {
res.status(400).send({message: 'content can not be empty'})
return
}
const user = new Userdb({
name: req.body.name,
author: req.body.author,
language: req.body.language,
date: req.body.date,
description: req.body.description
})
user
.save(user)
.then(data => {
// res.send(data)
res.redirect('/')
})
.catch(err => {
res.status(500).send({
message: err.message || 'some error occured'
})
})
}
exports.find = (req, res) => {
if (req.query.id) {
const id = req.query.id
Userdb.findById(id)
.then(data => {
if (!data) {
res.status(404).send({message: `error ${id}`})
} else {
res.send(data)
}
})
.catch(err => {
res.status(500).send({message: `error ${id}`})
})
} else {
Userdb.find()
.then(user => {
res.send(user)
})
.catch(err => {
res.status(500).send({message:err.message || 'error while finding data'})
})
}
}
exports.update = (req, res) => {
if (!req.body) {
return res.status(400).send({message: 'Data to update is empty'})
}
const id = req.params.id
Userdb.findByIdAndUpdate(id, req.body, {useFindAndModify: false})
.then(data => {
if (!data) {
res.status(404).send({message: `can't update ${id}`})
} else {
res.send(data)
}
})
.catch(err => {
res.status(500).send({message: 'err'})
})
}
exports.delete = (req, res) => {
const id = req.params.id
Userdb.findByIdAndDelete(id)
.then(data => {
if (!data) {
res.status(404).send({message: `${id} is wrong`})
} else {
res.send({message: 'user deleted'})
}
})
.catch(err => {
res.status(500).send({message: `could not delete with ${id}`})
})
}
This is server/routes/router.js
const route = express.Router()
const services = require('../services/render')
const controller = require('../controller/controller')
route.get('/', services.homeRoute)
route.get('/add-book', services.addNewBook)
route.get('/update-book', services.updateBook)
route.get('/updateBookRequest', services.updateBookRequest)
route.get('/delete-book', services.deleteBook)
// API
route.post('/api/books', controller.create)
route.get('/api/books', controller.find)
route.put('/api/books/:id', controller.update)
route.delete('/api/books/:id', controller.delete)
module.exports = route
This is server/services/render.js
const axios = require('axios')
exports.homeRoute = (req, res) => {
axios.get('http://localhost:5000/api/books')
.then(function(response) {
res.render('index', {books: response.data})
})
.catch(err => {
res.send(err)
})
}
exports.addNewBook = (req, res) => {
res.render('add_new_book')
}
exports.updateBook = (req, res) => {
axios.get('http://localhost:5000/api/books', {params:{id:req.query.id}})
.then(function(userdata) {
res.render('update_book', {book:userdata.data})
})
.catch(err => {
res.send(err)
})
}
exports.updateBookRequest = (req, res) => {
console.log(req)
axios.put(`http://localhost:5000/api/books/${req.query.id}`, {book:req.body})
.then(function(response) {
res.redirect('/')
})
.catch(err => {
res.send(err)
})
}
exports.deleteBook = (req, res) => {
axios.delete(`http://localhost:5000/api/books/${req.query.id}`)
.then(function(response) {
console.log('deleted')
res.redirect('/')
})
.catch(err => {
res.send(err)
})
}
This is by far the whole code
You need to use a callback in your update function. Also you can use {new: true} to get the updated document.
Userdb.findByIdAndUpdate(id,
req.body,
{useFindAndModify: false},
{new: true},
function (err, data) {
console.log(data); //check if the document is updated
}
})
Also make sure your req.body is an object. if you are unsure, check req.body in console log
I'm building a fullstack React + NodeJS to-do list app following a tutorial. I've created a React Task component that displays info for a particular task and provides update/delete buttons. For some reason, my React updateTask and deleteTask functions update/delete the oldest task regardless of which task I've selected to change.
I'm using the update state variable in React to toggle the update form.
Also, logging res in the updateTask function returns success and the correct id to update. However, this is not the id that actually gets updated.
React Task component (Task.js):
import React, { Component } from "react";
import axios from "axios";
class Task extends Component {
constructor({_id, title, due, desc}) {
super();
this.state = {
id: _id,
title: title,
due: due,
desc: desc,
update: false
}
this.updateTask = this.updateTask.bind(this);
this.deleteTask = this.deleteTask.bind(this);
}
updateTask = () => {
const {id, title, due, desc} = this.state;
axios.post("/tasks/update", {
id: id,
update: {
title: title,
due: due,
desc: desc
}
})
.then(
res => {
console.log(res);
console.log(res.data);
}
);
};
deleteTask = () => {
const {id} = this.state;
axios.delete("/tasks/delete", {
id: id
});
};
render() {
const {id, title, due, desc, update} = this.state;
return (
<div className="task">
<div>{id}</div>
{update ?
<div className="task-update">
<input
type="text"
onChange={e => this.setState({ title: e.target.value })}
value={title}
/>
<input
type="date"
onChange={e => this.setState({ due: e.target.value })}
value={!due ? "" : due.slice(0,10)}
/>
<textarea
onChange={e => this.setState({ desc: e.target.value })}
value={!desc ? "" : desc}
/>
<button onClick={this.updateTask}>
Update Task
</button>
</div>
:
<div className="task-show">
<div className="task-info">
<div>{title}</div>
<div>{!due ? "no date" : due.slice(0,10)}</div>
<p>{desc}</p>
</div>
<div className="task-btns">
<button
className="task-edit"
onClick={e => this.setState({update: true})}
>
</button>
<button
className="task-done"
onClick={() => this.doneTask()}
></button>
<button
className="task-del"
onClick={this.deleteTask}
>
</button>
</div>
</div>
}
</div>
);
}
}
export default Task;
NodeJS task controller:
var express = require('express');
var router = express.Router();
const Task = require("../models/task");
const Data = require("../models/data");
router.get("/all", (req, res) => {
Task.find((err, tasks) => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true, tasks: tasks });
});
});
router.post("/update", (req, res) => {
const { id, update } = req.body;
Task.findOneAndUpdate(id, update, err => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true, id: id});
});
});
router.delete("/delete", (req, res) => {
const { id } = req.body;
Task.findOneAndDelete(id, err => {
if (err) return res.send(err);
return res.json({ success: true });
});
});
router.post("/create", (req, res) => {
let task = new Task();
const {title, due, desc} = req.body;
if (!title) {
return res.json({
success: false,
error: "INVALID INPUTS"
});
}
task.title = title;
task.due = due;
task.desc = desc;
task.save(err => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true });
});
});
module.exports = router;
Thank you for the help in advance!
You should use Task.findOneAndUpdate({_id: id}, ...). If you don't use valid query like {_id: id}, it always returns the first object as far as I know.
Mogoose findOneAndUpdate accepts query as first parameter.More info here.
Try to update this.state.id onclick of delete task or pass in e.target.value to delete function and then pick the Id to the api call
I'm trying to make a React-Node.js application for practice. I encountered an problem in sending POST request. When I fetch POST request in App.js, it returns only id. I expected it to return 3 more values.
Current object
{ _id: 5a046d52bb5d37063b3c8b21 }
Ideal object
{_id: "59e9fed60fe8bf0d7fd4ac6e", name: "recipe1", ingredients: "apple", descriptions: "cut an apple"}
How should I add values to req.body correctly? I referred this solution Post an object with fetch using react js and express API server but it didn't work with my app.
index.js (node.js)
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const app = express();
// Serve static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));
app.use(bodyParser.urlencoded({ extended: true}));
var db
const MongoClient = require('mongodb').MongoClient
MongoClient.connect
('mongodb://Recipe:recipebox#ds125914.mlab.com:25914/ayumi', (err, database) => {
if (err) return console.log(err)
db = database
app.listen(8080, () => {
console.log('listening on 8080')
})
})
app.get('/api', (req,res)=> {
db.collection('recipe').find().toArray((err, results) => {
if(err) return console.log("no recipe");
res.json(results);
})
})
app.post('/recipe', (req,res)=>{
db.collection('recipe').save(req.body, (err, result) => {
if(err) return console.log(err);
console.log(req.body)
console.log('save to database');
res.redirect('/');
})
})
App.js (react)
class App extends Component {
constructor(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e){
e.preventDefault();
fetch('/recipe', {
method: 'POST',
body: JSON.stringify({
name: this.refs.name.value,
ingredients: this.refs.ingredients.value,
descriptions: this.refs.descriptions.value
}),
headers: {"Content-Type" : "application/json"}
})
.then((res)=> {
return res.json()
})
.then((body)=>{
console.log("body" + body)
console.log("result" + this.refs.name.value)
})
}
render() {
return (
<div className="App">
<h1>Recipe List</h1>
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="name" ref="name" />
<input type="text" placeholder="ingredients" ref="ingredients" />
<input type="text" placeholder="descriptions" ref="descriptions" />
<input type="submit"/>
</form>
</div>
)
}
}
export default App;
Server-side changes:
app.post('/recipe', (req, res) => {
// log the body of the request, to make sure data is properly passed
console.log(req.body);
// use mongodb's insertOne instead of the deprecated save
db.collection('recipe').insertOne(req.body, (err, result) => {
if (err) return console.log(err);
// log the result of db insertion
console.log(result);
console.log('saved to database');
// send the freshly saved record back to the front-end
res.json(result);
});
});
Front-end changes:
class App extends Component {
constructor(props){
super(props);
// add state to hold recipe returned from POST call
this.state = {
recipe: null,
name: '',
ingredients: '',
descriptions: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const { name, ingredients, descriptions } = this.state;
fetch('/recipe', {
method: 'POST',
body: JSON.stringify({
name,
ingredients,
descriptions
}),
headers: {"Content-Type" : "application/json"}
})
// when call completes, it should return the newly created recipe object
// as it was saved in the DB - just store it into state
.then((recipe)=> {
this.setState({recipe});
});
// TODO: handle error case
}
render() {
// added a paragraph tag to display the ID of the freshly created recipe
// it's only displayed if recipe is not null or undefined
// further changes: turning inputs into controlled inputs
const { name, ingredients, descriptions } = this.state;
return (
<div className="App">
<h1>Recipe List</h1>
<form onSubmit={this.handleSubmit}>
<input
value={name}
type="text"
onChange={e => this.setState({ name: e.target.value })}
placeholder="name" />
<input
value={ingredients}
type="text"
onChange={e => this.setState({ ingredients: e.target.value })}
placeholder="ingredients" />
<input
value={descriptions}
type="text"
onChange={e => this.setState({ descriptions: e.target.value })}
placeholder="descriptions" />
<input type="submit"/>
{ recipe &&
<p>Saved ID: {this.state.recipe._id}</p>
}
</form>
</div>
);
}
}
export default App;
Further changes: turned all three text inputs into controlled inputs (values of all 3 fields are tracked in state, and passed to fetch when the form is submitted).
I'm trying to add a business in Node Express Framework. My issue is that when I fill out the form to add the business, nothing adds to the page. Been trying to figure out this error for some time now.
My business.js code:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Business = require('../models/business');
var passport = require('passport');
// set up the GET handler for the main movies page
router.get('/', function(req, res, next) {
// use the Article model to retrieve all movies
Business.find(function (err, business) {
// if we have an error
if (err) {
console.log(err);
res.end(err);
}
else {
// we got data back
// show the view and pass the data to it
res.render('movies/index', {
title: 'Business',
business: business
});
}
});
});
// GET handler for add to display a blank form
router.get('/add', function(req, res, next) {
// new
if (req.isAuthenticated()) {
res.render('movies/add', {
title: 'Add a New Business'
});
}
else {
res.redirect('/auth/login');
}
});
// POST handler for add to process the form
router.post('/add', function(req, res, next) {
// save a new article using our Article model and mongoose
Business.create( {
name: req.body.name,
city: req.body.city,
province: req.body.province,
postal: req.body.postal,
street: req.body.street
}
);
// redirect to main business page
res.redirect('/business');
});
// GET handler for edit to show the populated form
router.get('/:id', function(req, res, next) {
// create an id variable to store the id from the url
var id = req.params.id;
// look up the selected article
Business.findById(id, function(err, business) {
if (err) {
console.log(err);
res.end(err);
}
else {
// show the edit view
res.render('movies/edit', {
title: 'Business Details',
business: business
});
}
});
});
// POST handler for edit to update the article
router.post('/:id', function(req, res, next) {
// create an id variable to store the id from the url
var id = req.params.id;
// fill the article object
var business = new Business( {
_id: id,
title: req.body.title,
content: req.body.content,
date: req.body.date,
rating: req.body.rating,
actor: req.body.actor
});
// use mongoose and our Article model to update
Business.update( { _id: id }, business, function(err) {
if (err) {
console.log(err)
res.end(err);
}
else {
res.redirect('/business');
}
});
});
//get handler for delete using the article id
router.get('/delete/:id', function(req, res, next){
//grab the id parameter from the url
var id = req.params.id;
Business.remove({ _id: id }, function(err) {
if(err) {
console.log(err);
res.end(err);
}
else {
// show updated business page with redirect
res.redirect('/business');
}
});
});
////auth check
//function isLoggedIn(req, res, next) {
// //is the user authenticated>
// if (req.isAuthenticated()) {
// return next();
// }
// else {
// res.redirect('/auth/login');
// }
//}
// make public
module.exports = router;
My add.ejs code:
<%- include ../partials/header.ejs %>
<main>
<form method="post" action="add">
<fieldset>
<label for="name">Name:*</label>
<input type="text" name="name" required />
</fieldset>
<fieldset>
<label for="city">City:*</label>
<input type="text" name="city" required>
</fieldset>
<fieldset>
<p>
<label>Province:*</label>
<select id="province" required>
<option value="--">--</option>
<option value = "ontario">ON</option>
<option value = "quebec">QC</option>
<option value = "british columbia">BC</option>
<option value = "alberta">AL</option>
<option value="nova scotia">NS</option>
<option value="manitoba">MB</option>
<option value="newfoundland">NL</option>
<option value="pei">PEI</option>
</select>
</p>
</fieldset>
<fieldset>
<label for="postal">Postal Code:*</label>
<input type="text" name="postal" required>
</fieldset>
<fieldset>
<label for="street">Street Name:*</label>
<input type="text" name="street" required>
</fieldset>
<button class="btn btn-primary" type="submit">Save</button>
</form>
</main>
</body>
</html>
Thanks so much in advance!