Unable to send user data to views - node.js

This is my general format for views:
<html>
<head></head>
<body>
<%- include('_header'); %>
<main>
(html code for a particular page)
</main>
<%- include('_footer'); %>
</body>
</html>
This is my code for _header.ejs:
<header>
<a id="logos" href="/">
<img id="dr" src="/imgs/logo.png" alt="logo">
</a>
<div id="nav_bar">
Achievements
Sponsors
Team
Gallery
<% if(profile_user.id) { %>
Profile
<% } else { %>
Log In
<% } %>
</div>
</header>
I have routes folder which gets controllers from different controllers. I am getting an error _header.ejs that profile_user.id is not defined.
11| Gallery
>> 12| <% if(profile_user) { %>
13| <%= profile_user.user %>
14| <% } else { %>
15| Log In
profile_user is not defined
Now the solution to this problem would be to use User.findOne() but then I don't want to do this for all controllers. I want to globalize profile_user into all views. Can you tell me how to do that?
Also, I have tried to do this by adding middleware and sending using it in my app.js but it never gets called.
console.log(10);
if (await req.isAuthenticated()) {
// req.user contains the current signed in user from the session cookie and we are just sending this to the locals for the views
res.locals.user = req.user;
console.log('Locals\' user loaded');
}
next();
}
In app.js I have called the function
app.use(passport.setAuthenticatedUser);
and updated the _header.ejs code to this:
<%= user.user %>
<% } else { %>
Log In
<% } %>
Solution to any of the two problems (through middleware or through controllers) will do.
Let me know if you need anything else

Related

Express nodejs Handlebars not rendering database content correctly inside EJS file

Im having a problem with my express nodejs project where the handlebars wont render on my ejs file. I created some handlebars which fetch some data from a database. When I render the hbs files the content from the database is displayed correctly, but when I include the hbs files in my ejs file together with my page header and footer the content from the database is not retrieved. I would appreciate any help.
cars.hbs
<!DOCTYPE html>
<html>
<body>
<p> The {{dbcars.model}} features a {{dbcars.specs.engine}} engine... </p>
</body>
</html>
home.ejs
<body>
<p> <%- include('navbar.ejs') %> </p>
<p> <%- include('handlebars/cars.hbs') %> </p>
<p> <%- include('footer.ejs') %> </p>
</body>
</html>
(note: when I render (handlebars/cars.hbs) instead of (home.ejs) the handlebars render correctly. )
car.js
router.get('/vehicle/:id', async (req, res) => {
Car.findById(req.params.id, function(err, carRouter) {
res.render("home.ejs", {
dbcar: carRouter
})
This is the result im getting:
(navbar)
The {{dbcars.model}} features a {{dbcars.specs.engine}} engine...
(footer)
This is the result im trying to get:
(navbar)
The Nissan Sentra features a 2.0 L 4-cylinder engine...
(footer)
You should create cars.ejs as well
cars.ejs
<% if (dbcar.length > 0) { %>
<% dbcar.forEach(dbcars => { %>
<p> The <%= dbcars.model %> features a <%= dbcars.specs.engine %> engine... </p>
<% }) %>
<% } else { %>
<p>There is no information to display.</p>
<% } %>
home.ejs
<%- include('handlebars/cars.ejs'); %>
car.js
router.get('/vehicle/:id', async (req, res) => {
Car.findById(req.params.id, function(err, carRouter) {
res.render("cars.ejs", {
dbcar: carRouter
})
};
};

get data in a ejs include with express-partials

I want to pass data to a include in ejs layout. I'm using express and express-partials
In the controller.js I have this:
exports.index = function(req, res, next) {
res.render('index', {uptime:'3'});
};
this is layout.ejs:
<!DOCTYPE html>
<html>
<head>
<%- include head %>
</head>
<header>
<%- include nav %>
</header>
<body>
<section>
<%- body %>
</section>
</body>
<footer>
</footer>
</html>
this is nav.ejs:
<li><%= uptime %></li>
and i get this error:
ReferenceError: /root/apps/webpanel/webpanel/views/nav.ejs:23
21| </li>
22| </ul>
>> 23| <li><%= uptime %></li>
24|
25|
26|
uptime is not defined
if I put the uptime in index.ejs the error disappears, but I want to get different views for nav and body...
What is the best solution to work correctly? or what i'm doing wrong?:/
Thank you!!
Maybe in this code : res.render('index', { uptime : '3'});
you choose to render the index.ejs
but the uptime key in layout.ejs
you said res.render('layout', { uptime: '3'}); does well
You should understand the first param of .render() meaning and ensure which template you need to render.
I suggest you to put in session, for access in some route, somelike:
exports.index = function(req, res, next) {
req.session.uptime = 3;
res.render('index');
};
And:
<li><%= session.uptime %></li>

How do i pass a user object to a partials in ejs?

I'm trying to render a user's name on a navbar, but that navbar is in a partial folder and none of the routes in node.js renders navbar.ejs because it is just a partial. I'm using ejs-mate library for having a reusable layout component to be used for other's html components so that I don't need to copy and paste codes (Following the DRY principle), why? because ejs doesn't have a built in reusable layout component's feature, and other libraries are not maintained by other developers.
Currently
I have two routes
app.get('/', passport.isAuthenticated, function(req, res) {
res.render('home' {
user: req.user
});
});
app.get('/anotherRoute', function(req, res) {
res.render('test');
});
I have two ejs files
home.ejs
<%- layout('boilerplate') %>
<h1>Home Page</h1>
another.ejs
<%- layout('boilerplate') %>
<h1>Another Page</h1>
Those two ejs files are using boilerplate.ejs for the layout, so I don't to copy and paste the same codes over and over again.
boilerplate.ejs - In this file I have include navbar and some other partials.
<!DOCTYPE html>
<html lang="en">
<head>
<% include ./partials/navbar %>
</head>
<body>
<header>
<% include ./partials/header %>
</header>
<div class="container">
<main>
<%- body -%>
</main>
<footer>
<% include ./partials/footer %>
</footer>
</div>
</body>
</html>
This is the navbar file, and take a look at the navbar-right class,
if user is logged in render name
else render about and signup
navbar.ejs
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">
StartupClone
</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li>About</li>
<% if (!user) { %>
<li>Signup</li>
<li>Login</li>
</ul>
<% } else{ %>
<li><a><%= user.profile.name %></a></li>
<% } %>
</div>
</nav>
The problem right now it is only working with a route that i pass a user's object to but not other routes. I know that I have to pass the user's object to every single route but it is not good because again I have to copy and paste the codes again in every single route which is against the DRY principle,
Imagine if have 40 routes that need to use that navbar, it would be a nightmare for me :(
If you guys have any idea on how to hack this, feel free to lend your thoughts on how to tackle this problem.
It is compulsory to pass the object you are trying to access on the view.
One thing you could do is store user object in session and in view check session for user object.
That way you will have to pass just the session object atleast I use this trick for this problem.
In your middleware passport.isAuthenticated on succesful login save the user object in session
module.exports.isAuthenticated = function(req, res, next) {
/*
check for valid credentials
*/
if (success)
{
req.session.user = foundUserInfo;
}
next();
}
and in your partial view
<!-- navbar.ejs -->
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">
StartupClone
</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li>About</li>
<% if (!session.user) { %>
<li>Signup</li>
<li>Login</li>
</ul>
<% } else{ %>
<li><a><%= session.user.profile.name %></a></li>
<% } %>
</div>
Now you just have to pass session object for each route.
app.get('/', passport.isAuthenticated, function(req, res) {
res.render('home' {
user: req.user,
session: req.session
});
});
app.get('/anotherRoute', function(req, res) {
res.render('test', {session: null});
});
You have to pass an object that has the used properties for each res.render() call, there's no way around it. It's even in the usage example in ejs-mate's documentation.
Having said that, there is a way to keep your code DRY. Use a function that sets shared properties on an input object, then for each route set the unique properties it requires:
function setSharedProperties(req, data) {
if(!(data instanceof Object)) {
data = {};
}
data.user = req.user;
return data;
}
app.get('/', passport.isAuthenticated, function(req, res) {
res.render('home', setSharedProperties(req))
});
app.get('/anotherRoute', function(req, res) {
res.render('test', setSharedProperties(req, {prop1: val1}));
});

EJS and Node, EJS throws an error if passed in object does not exist?

I am trying to pass a message object to a template using ejs. My route code is as follows:
app.get('/', function(req, res) {
res.render('index.ejs', {message: 'A message'});
});
In my ejs (index.ejs) file, I have:
<% if (message) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>
But when I do not pass an object at all (not just message: "") it returns the following error:
ReferenceError: /Users/Documents/node/views/index.ejs:13
11| <body>
12| <div class="container">
>> 13| <% if (message) { %>
14| <div class="alert alert-danger"><%= message %></div>
15| <% } %>
16| <div class="jumbotron text-center">
message is not defined
Similarly, if I try if(message.length > 0) but that just gives me the same error. I thought the whole point of an if statement would be that the if message doesn't exist, it just skips. How can I just make ejs render nothing if the message object is not passed or do I have to pass an empty message obect each time?
Explicitly check whether or not message is defined. This fixes it:
<% if (typeof message !== 'undefined' && message.length > 0) { %>
<div class="alert-danger"><%= message %></div>
<% } %>

Storing Express data in global variable through view

I have a data object "bootstrappedUser" being passed into the view through a route.
app.get('/', function(req, res) {
res.render('index.ejs',{
bootstrappedUser: req.user,
page: 'rest'
});
});
I'd like to store the "bootstrappedUser" JSON object into a global variable and use that variable to keep persistent login. Currently the window.bootstrappedUserObject is being accessed when bootstrappedUser is defined but it is not being set to anything.
<% if (bootstrappedUser!= undefined) { %>
<script>
window.bootstrappedUserObject = <% bootstrappedUser %>
</script>
<% } %>
I am receiving the following source code on login
<script>
window.bootstrappedUserObject =
</script>
You want to use <%= %> instead of <% %>:
<% if (bootstrappedUser!= undefined) { %>
<script>
window.bootstrappedUserObject = <%= bootstrappedUser %>
</script>
<% } %>
<% %> just evaluates JavaScript whereas <%= %> interpolates the result of an expression into your template.

Resources