Use a variable in a Jade include

node.jsExpressPug

node.js Problem Overview


I'm working with Jade and Express and I would like to use a variable in my include statement. For example:

app.js

app.get('/admin', function (req, res) {
  var Admin = require('./routes/admin/app').Admin;

  res.render(Admin.view, {
    title: 'Admin',
    page: 'admin'
  });
});

layout.jade

- var templates = page + '/templates/'

include templates

When I do this I get the error EBADF, Bad file descriptor 'templates.jade'

I even tried

include #{templates}

to no avail.

node.js Solutions


Solution 1 - node.js

AFAIK JADE does not support dynamic including. What I suggest is to "include" outside the template, i.e.

app.js

app.get('/admin', function (req, res) {
    var Admin = require('./routes/admin/app').Admin;
    var page = 'admin';

    var templates = page + '/templates/';

    // render template and store the result in html variable
    res.render(templates, function(err, html) {

        res.render(Admin.view, {
            title: 'Admin',
            page: page,
            html: html
        });

    });

});

layout.jade

|!{ html }

Solution 2 - node.js

this also works:

//controller
var jade = require('jade');
res.render('show', {templateRender: jade.renderFile});


//template
!= templateRender('my/path/'+dynamic+'.jade', options)

This probably will not increase the performance that you would expect from using the 'view cache' setting (it's on by default in NODE_ENV === 'production'). Or even break the app (e.g. if files are not available on the hard drive while deploying new code). Also trying to use this trick in a client-side or isomorphic app will not work because the template can not be compiled.

Solution 3 - node.js

Found this page googling for the same question, but in a different context, so thought I'd put my solution (read: workaround) here for posterity:

I wanted to surround my include with more context pulled from the variable, e.g. (simplified):

- var templates = page + '/templates/'
- var headid = page + 'head'
- var imgsrc = '/images/' + page
div(id=headid)    
  h1 #{page}
  img(src=imgsrc)
div(id=page)
  include templates

Since that doesn't work (Jade doesn't support dynamic includes, as noted by freakish), I hybridized with a mixin:

(Edit– a little more elegant than my previous workaround:)

mixin page1
  include page1/templates

mixin page2
  include page2/templates

...

- for (var i = 0; i < 3; i++)
  - var page = 'page' + i
  - var headid = page + 'head'
  - var imgsrc = '/images/' + page
  div(id=headid)    
    h1 #{page}
    img(src=imgsrc)
  div(id=page)
    +page

My previous answer:

mixin templates(page)
  - var headid = page + 'head'
  - var imgsrc = '/images/' + page
  div(id=headid)    
    h1 #{page}
    img(src=imgsrc)

+templates('page1')
#page1
  include page1/templates/

+templates('page2')
#page2
  include page2/templates/

...

It's not elegant, and it won't work if you need to include more than a few things this way, but at least part of the Jade is dynamic.

Solution 4 - node.js

Why do not use jade inheritance?

Render what you want at middleware level:

res.render('templates/' + template_name + '.jade')

Write common common.jade:

h1 This is a page
.container
  block sublevel
    h2 Default content

Then write file that extends common.jade:

extends common.jade
block sublevel
  h2 Some things are here

Solution 5 - node.js

It's 2019 and using variables in Pug (previously Jade) mixins has become simple.

When creating your mixin, you can give it parameters as per value(s) you're expecting to pass to the mixin. You can access any nested values using dot notation.

mixinFile.pug:

mixin myMixin(parameter1, parameter2, parameter3)
    h2.MyHeading #{parameter1}
	p.MyParagraph #{parameter2.myVariable}
    .MyBox(id= parameter3.id)

index.pug:

include mixinFile
block content
    +MyMixin(variable1, variable2, variable3)

You can read more in the official Pug documentation on Mixins.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSpencer CarnageView Question on Stackoverflow
Solution 1 - node.jsfreakishView Answer on Stackoverflow
Solution 2 - node.jsantpawView Answer on Stackoverflow
Solution 3 - node.jsFrijolView Answer on Stackoverflow
Solution 4 - node.jsuser2956171View Answer on Stackoverflow
Solution 5 - node.jsdanefondoView Answer on Stackoverflow