call node function, from ejs form - node.js

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
});

Related

req.flash not showing message

I'm using Handlebars in my express project. and I use req.flash() method but it won't Show up in my hbs file.
Here's my Code :
req.flash('message','Tag already exists');
res.redirect('/p/tags/add');
In .hbs file :
{{#if message}}
<h1>Tag Already ِExists</h1>
{{/if}}
Also in my app.js :
app.use(flash());
What Seems to be the problem?
Thanks in advance!
You need to use your flash message inside your redirected URL like this:
app.get('/p/tags/add', function(req, res){
res.render('yourhbsfile', { message: req.flash('message') });
});
EDIT: So to clarify about the confusion on flash message, it can be set from anywhere before redirecting to any route or inside any middleware before using res.render() and can propagate that message inside req or request object. you may print req and check flash object for better understanding.
It's true you can't add flash with redirection.
You have to execute flash function before redirection and then you have to use it inside the render function.
boo = (req, res) => {
req.flash("error", "This is an error!");
return res.redirect("/index");
}
Im using Routes, when viewing the /index page the indexPage function is executed.
Render function to view /index page.
indexPage = (req, res) => {
let message = req.flash();
res.render("index", {
message: message,
});
}
And how to view the data in Handlebar index.hbs
{{#if message.error}}
{{{message.error}}}
{{/if}}

NodeJS (Express) - app.delete route not working

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!

Beginner Node.js routing upon on submit

Just starting to play with node, and having a little bit trouble on routing, I looked on the routing separation example but thought it was a little bit advance for my skill, so I did in the following way, would anyone advice on the following code
index.html
<div class="container" id="test-container">
<h1>Test</h1>
<span id="test-error"></span>
<form id="test-input2">
<input type="text" id="test"></input>
</form>
</div>
ui.js
$('#test-input').submit(function(e){
e.preventDefault();
socket.emit('route', null);
});
ui_backend.js
exports.listen = function(server){
io = socketio.listen(server);
io.set('log level', 2);
io.sockets.on('connection', function(socket){
route_testing(socket);
});
}
function route_testing(socket){
socket.on('route', function(req, res){
res.render('test', function(err, html){
});
})
}
server.js
app.get('/test', function(req, res){
res.sendfile(__dirname + '/views/test.html');
});
Edit:
The problem is that I cannot get the routing to work.
Suggestion:
You setup a route in your server.js
app.get("/test", routes.page("test"));
In your ui_backend.js
module.exports = function (view) {
return function (req, res) {
res.render(view + ".html", {
page: view
});
};
};
Just do res.render() is fine. sendfile is not what you want.
function route_testing(socket){
socket.on('route', function(req, res){
res.render('test', function(err, html){
});
})
}
with socket.on(message,callback) , there is no req,res arguments. You are mixing up express and socket.io api.
on a socket message you need to emit another socket message. socket.emit(message)
socket.on('route', function(data){
socket.emit(message,somedata);
})
You basically have a server with 2 different protocols here, websockets and classic http.
The socket.io api is pretty clear: http://socket.io/ you cant make up a different api and expect it to work.
app.get('/test', function(req, res){
res.sendfile(__dirname + '/views/test.html');
});
sends /views/test.html as an attachement. You dont want to do that,you want express to render some html template or page:
app.get('/test', function(req, res){
res.render('test');
});
should work out of the box with a default express script.
So when you want to query over http, use the express api.
when you want to send message through websockets,use socket.io api.

callback in multiparty form parsing is not executed, seems (express 3)

I am learning to handle file upload in express 3.
module.exports.upload is my route handler for POST request to '/image/upload' :
var multiparty = require('multiparty');
module.exports.uploadPage = function (req, res) {
res.render('image/image', {file_content: null });
}
module.exports.upload = function (req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files){
console.log('inside form parsing call back');
res.writeHead(200, {'content-type': 'text/plain'});
res.end('received upload:\n\n');
});
if(req.method == 'GET') res.render('image/image');
}
this is my form:
<form action="/image/upload" enctype="multipart/form-data" method="post">
<input type="file" name="thumbnail" multiple="multiple" />
<input type="submit"/>
</form>
the console.log('inside form parsing call back'); is never executed since nothing is logged in terminal. I am using dev setting, the POST request log is even not logged to console.
Btw, I compared my code with example here. I beleive I am doing it right, but I can be wrong.
The callback seems not to be executed in this situation. Where went wrong?
Thank you!
Let me answer my question. The above code is good, but the reason it doesn't work is because I added
app.use(express.multipart());
in app.js
then add
var multiparty = require('multiparty');
again in the controller, which is image.js
This may not be helpful to you, but the take away is that only load(require(...)) multiparty where it needs to process forms. Don't use app.use, use require as this document suggests:
multiparty on github

What's the difference between "app.render" and "res.render" in express.js?

Docs for app.render:
Render a view with a callback responding with the rendered string. This is the app-level variant of res.render(), and otherwise behaves the same way.
Docs for res.render:
Render a view with a callback responding with the rendered string. When an error occurs next(err) is invoked internally. When a callback is provided both the possible error and rendered string are passed, and no automated response is performed.
How can I figure out when to use which one?
Here are some differences:
You can call app.render on root level and res.render only inside a route/middleware.
app.render always returns the html in the callback function, whereas res.render does so only when you've specified the callback function as your third parameter. If you call res.render without the third parameter/callback function the rendered html is sent to the client with a status code of 200.
Take a look at the following examples.
app.render
app.render('index', {title: 'res vs app render'}, function(err, html) {
console.log(html)
});
// logs the following string (from default index.jade)
<!DOCTYPE html><html><head><title>res vs app render</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>res vs app render</h1><p>Welcome to res vs app render</p></body></html>
res.render without third parameter
app.get('/render', function(req, res) {
res.render('index', {title: 'res vs app render'})
})
// also renders index.jade but sends it to the client
// with status 200 and content-type text/html on GET /render
res.render with third parameter
app.get('/render', function(req, res) {
res.render('index', {title: 'res vs app render'}, function(err, html) {
console.log(html);
res.send('done');
})
})
// logs the same as app.render and sends "done" to the client instead
// of the content of index.jade
res.render uses app.render internally to render template files.
You can use the render functions to create html emails. Depending on your structure of your app, you might not always have acces to the app object.
For example inside an external route:
app.js
var routes = require('routes');
app.get('/mail', function(req, res) {
// app object is available -> app.render
})
app.get('/sendmail', routes.sendmail);
routes.js
exports.sendmail = function(req, res) {
// can't use app.render -> therefore res.render
}
use app.render in scenarios where you need to render a view but not send it to a client via http. html emails springs to mind.
along with these two variants, there is also jade.renderFile which generates html that need not be passed to the client.
usage-
var jade = require('jade');
exports.getJson = getJson;
function getJson(req, res) {
var html = jade.renderFile('views/test.jade', {some:'json'});
res.send({message: 'i sent json'});
}
getJson() is available as a route in app.js.

Resources