Finding current url inside EJS view when using express

As far as I know, you can't do what you're asking for unless you modify EJS internally. However, a less bothersome solution would be to pass the URL property of the request on each page invocation, rather than define it per route.

app.get('/url', function (req, res) {
  res.render('view', {
    page: req.url,
    nav: {
      'Page 1': '/page1',
      'Page 2': '/page2',
      'Page 3': '/page3'
    }
  });
});

If you only wanted to get the first part of the URL and match it, then you could just call split('/') on req.url. You could then put a loop inside your template file to create the list for your navigation bar.

<% nav.forEach(function(title) { %>
  <% if (nav[title] == page) { %>
    <li class="active">This part of the navigation bar is active.</li>
  <% } else { %>
    <li>This part of the navigation bar is normal.</li>
  <% } %>
<% }) %>

In pretty much every node/express templating language I've used (ejs, kiwi, swig, jade), the answer is no. I've always just set a variable called "active" and then checked for it. As you say, it's not a great answer, though I don't know that scalability is the issue. If every url renders it's own view (or even if you have a common handler for view rendering), it shouldn't be that hard to say something like req.active = "Somepage". Another possibility would be to add middleware that does it for you based on the route. Something like

app.use(function(req, res, next){
    req.active = req.path.split('/')[1] // [0] will be empty since routes start with '/'
    next();
});

Then you just make sure any routes that have a corresponding nav component use unique paths, like

app.get('/students', ....)
app.get('/classes', ....)
app.get('/teachers', ....)
// etc.

EDIT: In response to your comment, I always throw ALL my view stuff into one object key inside req, and usually I name the key by whatever templater I'm using. So I would probably actually use the above example to set req.ejs.active and then do

res.render('myview', req.ejs);

This method makes it much easier to separate logic out into multiple middleware functions and not have to pass a huge anonymous object to res.render.


index.js

/* object menu */
const menu = [
    {
        name: 'Home',
        url: '/'
    },
    {
        name: 'About',
        url: '/about'
    }
]

/* route */
app.get( '/', function( request, response) {

    let data = {
        title: 'Home',
        url: request.url,
        menu: menu
    }

    response.render( 'home', data )

} )

app.get( '/about', function( request, response) {

    let data = {
        title: 'About',
        url: request.url,
        menu: menu
    }

    response.render( 'about', data )

} )

menu.js

    <% for ( let i in menu ) { %> // loop menu
        <% if ( menu[i].url == url ) { %> // match, add active in class

            <a class="active" href="<%= menu[i].url %>" ><%= menu[i].name %></a>

        <% } else { %>

            <a class="" href="<%= menu[i].url %>" ><%= menu[i].name %></a>

        <% } %>
    <% } %>