Jack Moscovi
Jack Moscovi

Reputation: 2269

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><a href="/">About</a></li>
            <% if (!user) { %>

            <li><a href="/signup">Signup</a></li>
            <li><a href="/login">Login</a></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.

Upvotes: 0

Views: 3339

Answers (2)

Amit
Amit

Reputation: 46351

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

Upvotes: 3

Riyaz Parve
Riyaz Parve

Reputation: 151

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><a href="/">About</a></li>
        <% if (!session.user) { %>

        <li><a href="/signup">Signup</a></li>
        <li><a href="/login">Login</a></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});
});

Upvotes: 2

Related Questions