Working on understanding CRUD basics with setting up simple routes from my HTML5 doc to Postgres database. My GET and POST buttons are working but my DELETE is not deleting from my database. I realize the routes all look very similar (and tried renaming them to see if it would hit the callback function that is linked to the database, but it didn't work). Can anyone tell me why my HTML5 form is not working with my route to reach the database for DELETE? Thanks!
I will only include the code I'm referring to as I have all the other code working well. Starting with showing the crappy HTML first, then the index.js with the routes, and then the queries.js with the database queries. ( ////// seperate the documents where the code is pulled :) )
<h1>Let's DELETE ONE Human</h1>
<form action="/users/:id" method="delete">
ID:<input type="number" name="id">
<input type="submit" name="">
</form>
/////////////////////////////////////////////////////////////////
app.get('/', (request, response) => {
response.sendFile(path.join(__dirname + '/html/homepage.html'))
}, db.getUsers)
app.get('/newHuman.html', (request, response) => {
response.sendFile(path.join(__dirname + '/html/newHuman.html'))
})
app.get('/users', db.getUsers)
app.get('/users/:id', db.getUserById)
app.post('/users', db.createUser)
app.put('/users/:id', db.updateUser)
app.delete('/users/:id', db.deleteUser)
app.listen(port, () => {
console.log(`App running on port ${port}.`)
})
////////////////////////////////////////////////////////////////////////
const deleteUser = (request, response) => {
const id = parseInt(request.query.id)
pool.query('DELETE FROM users WHERE id = $1', [id], (error, results) => {
if (error) {
throw error
}
response.status(200).send(`User deleted with ID: ${id}`)
})
}
TL;DR
How can I send to the correct route (even with just POSTing twice) from my HTML when the app.delete and app.put have the exact same route? Tried renaming route, didn't work but I know you shouldn't have to rename for it to work. Here are routes:
app.put('/users/:id', db.updateUser)
app.delete('/users/:id', db.deleteUser)
HTML form method only supports GET and POST method.
Either you have to use GET or POST or you can use ajax or some library like request or axios to make the DELETE request.
For example, if you use axios, try the following code.
Ignore importing jQuery and axios, if you already imported them.
<!-- import jQuery -->
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<!-- import axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<h1>Let's DELETE ONE Human</h1>
<form id='myFormId' action="/users/:id" method="delete">
ID:<input type="number" name="id" id='deleteId'>
<input type="submit" name="">
</form>
<script>
$( document ).ready(function() {
const myForm = $('#myFormId');
myForm.submit((event) => {
event.preventDefault();
const id = $('#deleteId').val();
const url = `/users/${id}`;
axios.delete(url)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
});
});
</script>
Another easier way of doing this is using a npm module called method-override.
In your main entry point file for your server, add the following lines:
const express = require('express');
const app = express();
const methodOverride = require('method-override');
app.use(methodOverride('_method'));
In your HTML form, you can now use PUT or DELETE requests easily:
For example:
<h1>Let's DELETE ONE Human</h1>
<form id='myFormId' action="/users/:id?_method=DELETE" method="delete">
ID:<input type="number" name="id" id='deleteId'>
<input type="submit" name="">
</form>
Notice the action attribute of the form, all you have to do now is add that simple line and you are done!
Related
Guys I have this logout button on my react app that executes the LogoutSession() function that goes like this:
<span onClick={LogoutSession} className="btn btn-light rounded-pill text-primary py-2
px-4 ms-lg-5">Log Out</span>
And this is the function:
const LogoutSession = (e) =>{
e.preventDefault();
Axios.get('http://localhost:3001/logout')
}
And in my server side (nodejs) I have this route:
router.get('/logout', async(req,res) => {
req.session.destroy();
console.log(req.session)
});
And I guess the problem is with the LogoutSession function cause I didn't know how to use Axios well to make that route work, is there any parameters that I'm missing or something I did wrong in the client side
Setting the session to null will also work:
req.session = null;
I know there are plenty of similar questions like my, but I couldn't find any solution for my problem.
I think the issue is that am not getting the product.html and I assume that there is also a problem with the redirection to the product.html.
product.html
<!DOCTYPE html>
<html>
<head>
<title>Product</title>
<meta charset="utf-8" />
</head>
<body>
<form id="product" action="/information" method="POST">
<label for="product_id">Enter product ID: </label>
<input id="product_id" name="product_id" type="text" required />
<input type="submit" />
</form>
</body>
</html>
index.js
const express = require("express");
// load data
const products = require("./data.json");
const app = express();
// static files
app.use(express.static("public"));
// form middleware
app.use(express.urlencoded({ extended: true }));
app.post("/information", (req, res) => {
// ES6 deconstruction syntax, get user input
const { product_id } = req.body;
// search product array
const product = products.find((product) => product.Product_ID === product_id);
if (product) res.json(product);
else res.send("product not found");
});
// redirect all GET requests to product form
app.get("*", (req, res) => {
res.redirect("/product.html");
});
app.listen(8000,console.log(`App listening at http://localhost:8000`));
When I run the code like above, I get the following error: The page isn’t redirecting properly
(Cookies & Cache is deleted). I even tried another project with a node.js server and the localhost in Firefox worked.
When I command the redirection out, I get this error: Cannot GET /
When I use "/" instead of "*" in the redirections, this error appears: Cannot GET /product.html
I don't understand why it doesn't get the product.html and why the redirection doesn't work right.
To render product.html for every endpoint, you can use sendFile rather than redirect, you will need to use path module, which is a core module to resolve the path to html file:
const path = require('path');
//your code
app.get('*', (req, res)=> {
//note that product.html file is in the same directory or you specify
//its relative path
res.sendFile(path.resolve(__dirname, 'product.html'))
})
I'm trying to use a simple POST request with Node using Express and instead am getting cannot POST with a 404. In the end I want to use ajax so it POSTs without refreshing the page in the browser, but first I need to get it running like this and I can't figure out what I've gotten wrong.
public/form.html
<!DOCTYPE html>
<form method="POST" action="">
<input name="firstName">
<input name="lastName">
<input type="submit">
</form>
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
//server running?
app.listen(3000,() => {
console.log('Started on PORT 3000');
})
//Serve the web page directory
app.use(express.static('./public'))
//Return form fields
app.post('form.html', (req, res) => {
console.log("First name: " + req.body.firstName)
console.log("Last name: " + req.body.lastName)
res.end()
})
app.post("/api", (req, res) => {
console.log("First name: " + req.body.firstName);
console.log("Last name: " + req.body.lastName);
res.end();
});
Here you have to make POST request to /api
<form method="POST" action="/api">
I've figured it out and will share in case others are looking for the same thing. The other responses are correct, but I was looking to POST without changing the URL. This doesn't look to be possible because I always get cannot POST and a 404 if I point to the existing page (either leaving action empty or using "#").
However, when you use AJAX, you still point to a new URL with the form action attribute and in your node app, but your AJAX code will keep the URL on the same page (the page doesn't refresh).
I'm making a very simple authenticated website for learning giving users the ability to create an account log in and view content.
The issue is not seeing the registered users on the home page (as a test) after a successful post registration. After the post, I am redirecting the user back to the home page and the get route runs a postgres function using node-postgres module to retrieve all of the users in the database and returns them. That doesn't seem to be firing. Yet, when I run the same function in my database, I do see the new user.
What's weird is that when I hit enter on the home route in the browser afterwards, the new user does pop up. So I'm really not sure if this is a caching thing or not understanding promises correctly (I've just started getting into this) or something else.
I have tried using callbacks instead of promises as shown on here: https://node-postgres.com/features/queries to see if it makes a difference. Other than that, I've added log statements to see if the promise actually resolves or rejects. But it seems to always resolve so I'm really unsure what's going on here.
<!-- register.ejs -->
<%- include('partials/header') %>
<div class="container mt-5">
<h1>Register</h1>
<div class="row">
<div class="col-sm-8">
<div class="card">
<div class="card-body">
<!-- Makes POST request to /register route -->
<form action="/register" method="POST">
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-dark">Register</button>
</form>
</div>
</div>
</div>
</div>
</div>
<%- include('partials/header') %>
\\index.js (in ./db)
const {
Pool
} = require('pg');
const pool = new Pool({
database: 'secrets'
});
module.exports = {
query: (text, params, callback) => {
return pool.query(text, params, callback)
}
};
//jshint esversion:6
/* Imports
* ================================================================================ */
const express = require('express');
const bodyParser = require('body-parser');
const db = require('./db');
const util = require('util');
/* App setup
* ================================================================================ */
const app = express();
app.disable('etag');
const port = 3000;
app.use(express.static(util.format("%s/%s", __dirname, 'public')));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
/* Routes
* ================================================================================ */
// Get request
app.get("/", function (req, res, next) {
db.query('SELECT * FROM dbo.usp_SelectUsers()')
.then(function(dbResult) {
console.log(dbResult.rows);
res.send(dbResult.rows);
}, (reason) => {
console.log("Not fulfilled :(");
}).catch(_err => next(_err));
});
// Post request for registration
app.post("/register", function (req, res, next) {
const queryText = 'SELECT dbo.usp_CreateUser($1, $2)';
const queryValues = [req.body.username, req.body.password];
db.query(queryText, queryValues)
.then(res.redirect("/"))
.catch(err => next(err))
});
CREATE OR REPLACE FUNCTION dbo.usp_SelectUsers()
RETURNS TABLE (User_ID INTEGER, User_Name VARCHAR(100)) AS
$func$
BEGIN
RETURN QUERY
SELECT u.User_ID
,u.User_Name
FROM dbo.User u
;
END
$func$ LANGUAGE plpgsql;
Expected result is to see new users in database and displayed on home page ("/") after successful post without having to refresh the page again.
I have updated my registration code to use async / await as follows and this fixed everything for me. I realized that the issue I was having previously is that the post did not fully complete before the database call to retrieve the the list of users were made (ie: database did not yet have the new user when calling dbo.usp_SelectUsers).
app.post("/register", async (req, res, next) => {
try {
const queryText = 'SELECT dbo.usp_CreateUser($1, $2)';
const queryValues = [req.body.username, req.body.password];
const results = await db.query(queryText, queryValues);
res.redirect("/login");
} catch (err) {
throw err;
}
});
As a side note, I have read that async / await is also much better to use nowadays and this fix added onto the pluses. Please see the following article for reference:
https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9
I'm making a node application where I need to call a function, written inside my app.js, and I need to call it from, a form, in a template, made with ejs.
i'm using node.js, express.js and ejs.
can anyone help?
You want to use ajax to interface with the server-side function:
$.get('/your_route', {data: 'goes here'}, function (res) {
console.log('callback after your node function is done')
})
You might call the function from the template by:
<form class="ajax_caller" onsubmit="do_ajax_call()">form goes here</form>
However that is not considered a good practice. This is much better:
// click event
$(document).on('submit', 'form.ajax_caller', do_ajax_call)
function do_ajax_call (e) {
e.preventDefault()
$.get('/your_route', {data: 'goes here'}, function (res) {
console.log('callback after your node function is done')
})
}
Ofcourse you will have to set up a route in express:
app.get('/your_route', function (req, res) {
finally_your_function()
res.send('finished')
});
If you don't want to use ajax, you can just set the action of the form to your ajax route, however that will redirect user to the route so you will have to handle that.
You can use regular HTML forms which submit their content to a certain URL on the server.
Example:
Add the form to HTML/EJS:
<form method="GET" action="/sampleUrl">
<input type="submit" name="submit">
</form>
Add the route to your app.js:
var express = require('express');
var app = express();
app.get('/sampleUrl', function(req, res) {
//Do something
});