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}}
Related
Let's say i have an index route:
router.get('/', (req, res) => {
res.render('index', {
title: 'Home',
etc: etc...
});
});
In this route i have a post from a form or something:
router.post('/', async(req, res) => {
const something = req.something;
await something.save(); //Save to database, it's just an example quick code
res.render('index', {
title: 'Home',
success: true,
etc: etc...
});
});
As you see i re-render the page with the success: true locals.
It is used in the templating for displaying a message.
However if the user refreshes the re-rendered page he will see the message again.
I'm using handlebars at clientside if that matters, like
<body>
...
{{#if success}}
<script>alert('Your data saved!')</script>
{{/if}}
</body>
Is it possible to send that "success" without a re-render, and without seeing it multiple times if the user refreshes the page? If i can avoid the re-rendering that would be good enough.
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
});
I've been playing with express js lately and I'm loving it. My problem is that when I submit an invalid form a validation error message appears but when I reload the page the error message is still displaying I think the error message is being cached. Is there a way to disable caching in jade / swig and also is there a way to just specify which pages to cache and not to cache(like the form)?
sample code:
filename: index.js
// app.get('/form', index.getForm)
exports.getForm = function(req, res){
res.render('form');
}
// app.post('/form', index.postForm)
exports.postForm = function(req, res){
// express form validation goes here ...
if(errors){
res.locals.errors = errors;
res.locals.form = req.body;
exports.getForm(req, res);
}else{
res.redirect('/welcome');
}
}
and here's my jade
filename: form.jade
if error.email
.error=error.email.msg
input#email(type='email', name='email', value='#{form.email}')
else
input#email(type='email', name='email', value='#{form.email}')
Theres no cache problems unless you are running express in production mode.
It looks like when you press F5, after the form error, your request is re-submiting the same form via post (with the error).
Option 1:
AJAX <3
Option 2:
Use 2 diferent jade templates, one for the exports.postForm with
errors and another for the exports.getForm. Something like:
exports.getForm = function(req, res) {
res.render('form');
}
exports.postForm = function(req, res) {
// express form validation goes here.
if(errors) {
res.locals.errors = errors;
res.locals.form = req.body;
res.render('form_fail'); <----
}
else {
res.redirect('/welcome');
}
}
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.
With Apache this this really easy, but with Node.JS I don't think so. Simply, I want that when a user click something like this: <a href="/dir/file.png">, he starts to download the file. When I do that, I'm redirected to http://foo.com/fir/file.png, and I visualize the photo. Also say that I have in the app configure this app.use(express.static(__dirname + '/public'));, so, the file is in the public path, and the public path is declared as static. And, when the users click, I dont want that he will be redirected and then the download starts.
I know this is posible, it's just click a link and a download starts! But I don't know how to do it.
Thank's advance!
EDITED:
The HTML where is the <a href="">for the download is here:
app.get('/:user/:id', function (req, res){
usermodel.findOne({ user: req.params.user }, function (err, user){
var imagen = user.imagen.id(req.params.id);
if (err) throw err;
res.render('photo.ejs', {
user: user,
photo: imagen,
});
});
});
Is necessary to create a new app.get? If I do that, I would get redirected? I'm trying to do this without getting redirected.
This depends on the headers you're sending with the image.
To make the browser download the image instead of displaying it, you need to set a "Content-Disposition: attachment" header.
Since you're using the static middleware, this is a bit trickier to do than in your own request handler function. You'll have to inject a middleware before the static one.
app.use(function(req, res, next) {
if (req.path.split('/')[0] === "downloads")
res.attachment(); //short for res.set('Content-Disposition', 'attachment')
next();
});
app.use(express.static(__dirname + '/public'));
Similarly to #rdrey's answer, make the browser download a file if there's ?dl query parameter in the url.
app.use('/gifs/*.gif', function(req, res, next) {
if (req.query.dl !== undefined) res.attachment();
next();
});
app.use('/gifs', express.static(__dirname + '/gifs'));