How do I use req.flash() with nunjucks? - node.js

I am using connect-flash to pass the flash message. In my controller, I am using the following code if (!req.user) {
req.flash("error_msg", "User not found !!");
return res.redirect(307, '/');
}
In my view, I tried
{{ error_message }}
{{ req.flash('error_message') }}
{{ req.flash.get('error_message') }}
But none of it works. What's the current syntax to parse the flash message in nunjucks ?

First of all you have to install "express-flash" and put below code in app.js
app.js
const flash = require('express-flash');
In Your Controller put below code when you want to pass message
req.flash('error_msg', "User not found !!");
return res.redirect(307, '/');
Put below code in your view file where you want to display message
<% if (typeof messages.error_msg !='undefined') { %>
<p class="error"><%= messages.error_msg %></p>
<% } %>

For anyone facing the same problem you can access the variable using {{ req.session.flash.error_msg }}

If you are using express js and nunjucks as template this is what I have done
in app.js
const flash = require('express-flash');
app.use(flash());
in Routes/controller code
try {
await User.deleteOne({_id:req.params._id}).exec()
req.flash("success_msg", "User deleted");
return res.redirect('/admin/users')
}
in Layout or view file
{% if messages.success_msg %}
<div class="alert alert-success" role="alert">
{{ messages.success_msg }}
</div>
{% endif %}

With connect-flash package, you cannot directly use req.flash in template engine. You need to add a middleware that adds the flash message to the res.locals which can be accessed in template rendering.
Here is a short code snippet.
// this part should be before all the request resolver.
// adding flash function to response locals
app.use((req,res,next)=>{
res.locals.flash = (arg) => { return req.flash(arg) };
next();
});
// request resolver
app.get("/",(req,res)=>{
req.flash("info","show me");
res.render("index.njk",{});
});
app.listen(8080,()=>{...})
In nunjucks file:
<h3>{{ flash("info") }}</h3>

Related

How do i make the ejs variable work that i send from nodejs?

I am tring to get a variable that i send from nodejs to ejs to work. But for some reason it wont, i cant figure out why.
This is the index.js:
var newOne = "Yes"
router.get('/main', ensureAuthenticated, (req, res) =>
res.render('main', {
user: req.user,
newOneInView : newOne
})
)
And this is in the main.ejs file:
<%if (newOneInView == "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
So what i am trying to achieve is that variable will be seen from the nodejs at the main.ejs page but some reason it wont change the image SRC. What am i doing wrong here?
In your template you need to make sure that you place the code for changing the src attribute in a script that is placed after the element (alternatively you can use a listener for the content to be loaded), e.g:
<body>
<img id="avatar" src="/some-other-path"/>
<script>
<% if (newOneInView === "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
</script>
</body>

Symfony 4 How to add an attribute to a twig using jquery?

I'm trying to do a form with symfony 4. It works fine. But I have a problem.
I have a field to write a comment. By default, it's not required.
However, I would like to change this using jquery.
This is what I tried to do.
Here, it's my twig:
<div class="information" id="informationForm">
{{ form_row(recordForm.category) }}
{{ form_row(recordForm.information) }}
{{ form_label(recordForm.comment) }}
{{ form_widget(recordForm.comment, {'attr': {'class': 'comment'}}) }}
{{ form_errors(recordForm.comment) }}
<button id="add_information_button" class="btn btn-primary">Ajouter un renseignement</button>
<button id="count_div" class="btn btn-primary">Compter</button>
<button class="remove_information_button btn btn-primary">Supprimer un renseignement</button>
</div>
Here it's the javascript:
$('.information')
.on("change", ".record_to_information_form_information", function (event) {
event.preventDefault();
var $commentState = $(this).find('option:selected').data('comment')
//Test: to know if i received the attribute
console.log($commentState)
if($commentState===false){
//the field isn't required
// {{ form_widget(recordForm.comment, {'attr': {'required': 'false'}}) }}
}else{
//the field is required
// {{ form_widget(recordForm.comment, {'attr': {'required': 'true'}}) }}
}
})
;
Do you have any suggestions?
You can toggle required property value from your jQuery code.
I assume that data-comment attribute has type boolean and it's always set, so your toggle statement can look as follows:
$('.information')
.on("change", ".record_to_information_form_information", function (event) {
event.preventDefault();
var $commentState = $(this).find('option:selected').data('comment');
//Test: to know if i received the attribute
console.log($commentState);
$('.comment').prop('required', $commentState);
});
If you need to do something else in your if-else statement, you can just leave your condition as you provided in sample:
if ($commentState === false) {
//the field isn't required
$('.comment').prop('required', false);
} else {
//the field is required
$('.comment').prop('required', true);
}

Unable to display flash message in view with ejs template

I am a newbie in NodeJS. I have a problem that I am unable to show flash message in my view.
Here is my Controller,
index : function(req, res){
res.locals.flash = _.clone(req.session.flash);
res.locals.layout = false;
res.view('login');
},
login : function(req, res){
....
if(!admin){
req.session.flash = {
err : 'User is not found.' // My flash message
}
res.locals.layout = false;
res.redirect('login');
return;
}
.....
}
Here is my view,
<% if(flash && flash.err) { %>
<div class="alert alert-danger">
<% JSON.stringify(flash.err) %>
</div>
<% } %>
When login is false, it show only an empty alert box.
And I have a second problem. When I refresh page, The alert box isn't disappeared.
Could someone help me please.
Thanks a lot.
The alert box keeps on appearing because the req.session.flash object persists the session, so you need to null that out once it's used, or you can just simply use req.flash(), which does that for you. So change your index method to something like this:
index: function(req, res) {
// req.flash() returns the contents of req.session.flash and flushes it
// so it doesn't appear on next page load. No need to clone.
res.locals.flash = req.flash();
res.locals.layout = false;
res.view('login');
},
Now, onto the second problem. The error messages aren't appearing because you aren't using the proper EJS syntax to output escaped values into the view. All you need to do is change your code to this:
<% if(flash && flash.err) { %>
<div class="alert alert-danger">
// Change <% to <%=
<%= flash.err %>
</div>
<% } %>
No need to JSON.stringify, unless you like the quotes. Notice that I changed the <% to <%=, which in EJS means "escape this and output it". It's not template HTML or anything like that, so it's okay to escape it anyway.

MEAN correct way to refactor ejs express code

I've created a website with express and ejs, pulling JSON in from a file in a local file. I'd like to pass the data in from a mongo database and display with an Angular view. I have a good amount of knowledge in express, angular and mongo. Putting it all together and separating the express tasks from the angular tasks has me hung up a bit.
My app is working over in Heroku at http://healingcenter.herokuapp.com/services/ this is the page I'm unclear on how to separate the express and angular tasks.
It is currently set up in express, this was before I researched angular and the MEAN stack. below is the route config.
router.get('/services', function(req, res) {
var myServices = [];
var entireList = [];
entireList = appdata.services;
appdata.services.forEach(function(item) {
myServices = myServices.concat(item.title);
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesList'
});
});
/* GET services detail page. */
router.get('/services/:servicesid', function(req, res) {
var myServices = [];
var entireList = [];
appdata.services.forEach(function(item){
if (item.shortname == req.params.servicesid){
entireList.push(item);
myServices = myServices.concat(item.title);
}
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesDetail'
});
});
This is pulling in the same data.json file from the app.js file with this line of code.
app.locals.appdata = require('./data.json');
The page variable is the important part. An if else statement is customizing which data is brought in. That code is here:
<div class="services">
<% list.forEach(function(item){ %>
<article class="service group">
<% if (page!= 'servicesDetail') { %>
<h3><%= item.title %></h3>
<p><%- item.summary %></p>
more
<% }else{ %>
<a class="back" href="/services/#"><i class="fa fa-chevron-circle-left"></i> back</a>
<h3><%= item.title %></h3>
<p><%- item.description %></p>
<% } %>
</article>
<% }); %>
</div>

Nodejs use method in view

For example,In my Nodejs app,I have a router:
exports.test=function(req,res){
res.render('./admin/test.jade',{html:[a,b,c]);
}
And I have Underscore.js
In my view test.jade:
-var _und=require('Underscore.js')
....
div
-_und.each(html,function(m))
span m
....
But I got error.This shows that,the Underscore.js is just be used as a server-side method,how can I use a server-side method in view?
You don't need to require underscore from a view. To view you should send just data (it means that in idea case you should not use underscore there at all). But if you would like, you can still send underscore like a function to view:
exports.test = function(req,res) {
res.render('./admin/test.jade',{ html: [a,b,c], _ : require("underscore") });
};
or like this:
exports.test = function(req,res) {
var underscore = require("underscore");
res.render('./admin/test.jade', { html : [a,b,c], _ : underscore });
}
After in your view you can access to that like this:
div
-_und.each(html,function(m))
span m
You can get inspired from my nodejs github markdown project (http://bit.ly/1aOAG35). There is used underscore for layouting and I'm using it as well in templates:
{{# onlyblogs.forEach(function(current){ }}
<li>
{{ current.title }}
{{# if (current.description){ }}
<span>{{ current.description }}</span>
{{# } }}
<span>{{ current.category }}</span> in <date>{{ current.date }}</date>.
</li>
{{# }); }}
Hope that it helped.

Resources