Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Add dynamic include (from variable) #93

Open
phplego opened this Issue Jan 1, 2013 · 57 comments

Comments

Projects
None yet

phplego commented Jan 1, 2013

For support <% include var_name %>
Please change this code (file ejs.js at line ~ 155):

  if (0 == js.trim().indexOf('include')) {
    var name = js.trim().slice(7).trim();
    if (!filename) throw new Error('filename option is required for includes');
    var path = resolveInclude(name, filename);
    include = read(path, 'utf8');
    include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug });
    buf.push("' + (function(){" + include + "})() + '");
    js = '';
  }

To this code:

  if (0 == js.trim().indexOf('include')) {
    var name = js.trim().slice(7).trim();
    if (!filename) throw new Error('filename option is required for includes');
    // If it is not path, but variable name (Added)
    if(options[name])
         var path = resolveInclude(options[name], filename);
    else
         var path = resolveInclude(name, filename);
    include = read(path, 'utf8');
    include = exports.parse(include, options); // Added transfer whole options
    buf.push("' + (function(){" + include + "})() + '");
    js = '';
  }

Эти два небольших исправления добавляют возможность использовать переменные в теге
<% include var_name %>

EDIT: File: node_modules/lib/ejs.js at line ~ 155

what file did you make this change in, i also need this functionality

Yeah I would also appreciate this feature 👍

This would be incredibly useful.

Same here

z5h commented Nov 27, 2013

+1

+1, please

+1 :)

+1

This code is wrong btw.

if (0 == js.trim().indexOf('include')) {
    var name = js.trim().slice(7).trim();
    if (!filename) throw new Error('filename option is required for includes');
    // If it is not path, but variable name (Added)
    if(options[name])
         var path = resolveInclude(options[name], filename);
    else
         var path = resolveInclude(name, filename);
    include = read(path, 'utf8');
    include = exports.parse(include, options); // Added transfer whole options
    buf.push("' + (function(){" + include + "})() + '");
    js = '';
  }

In this line,

buf.push("' + (function(){" + include + "})() + '");

buf is a string which does not have a push method. It should be changed to this to work

buf. += "' + (function(){" + include + "})() + '";

For those wondering where to add this code:
node.js - it should be added to node_modules/lib/ejs.js at line:155
in browser - it should be added to the ejs.js file before minification at line:207

I changed the code and made a pull request :)

+1

elyran commented Mar 10, 2014

I'd also like to have this functionality. Pull request #156 actually breaks my code for some reason.

@jasper-lyons buf is an array as defined at the top of the parse function.

mscdex commented Apr 2, 2014

I'm not too thrilled about the magic in #156, I'd rather see a separate token (e.g. 'include_dyn') for this behavior to make it very clear what is expected.

@visionmedia Any chance of including this kind of behavior in some way? I dislike maintaining forks for small changes like this and this particular feature seems to be desired by quite a few people.

elyran commented Apr 2, 2014

@mscdex +1 Absolutely correct!

@cjmarkham In the code base I made the fork from buf is most certainly a string, please feel free to have a look.

@mscdex On reflection I agree, I had a need for the functionality and it seemed a lot of others did too so I merely adapted @phplego 's code.

+1

+1

iZhen commented Apr 26, 2014

+1

jqsjqs commented Apr 27, 2014

Hi... the original solution works quite well for a single property of the "options" object (i.e., object.property1 is resolvable via options["property1"]). This doesn't work quite so well if I include an object in options that itself has properties. The use case here is that I have 5 or 6 templates I'm using to construct a page and rather include a var for each path at the root of the "options" object, I'd rather be able to specify the property of an object within "options" (i.e., <% include myObj.headers %> ).

I'm in a bit of a hurry tonight, so this won't be the most elegant code, but it does work and covers the original use case. Note that it does split and evaluate literal filenames to determine if they're in the options obj... so if you happen to create an object within "options" like this: options.filename-stem.ejs then whatever value is in there will take precedence. :)

   var resolvedObj = null;
   var objName = name.split(".");
   if (objName) {
       resolvedObj = options;
       for (var idx=0; idx<objName.length; idx++) {
           resolvedObj = resolvedObj[objName[idx]];
           if ( ! resolvedObj) {break;}
       }
   }

   if(resolvedObj)
        var path = resolveInclude(resolvedObj, filename);
   else
        var path = resolveInclude(name, filename);

Using this code, where do I put the variables to user for <% include myVar %> ?

mhandb commented May 19, 2014

+1

dgmike commented May 19, 2014

What's the difference between <% include file %> and <% include variable %>?

I have a system where users can create dynamic content using a WYSIWYG editor, which is saved in an HTML file. I want to be able to display a list of all of the user generated content at runtime without knowing the files at compile time.

For instance, I'd be able to like to write code in ejs like this:

<% for (i = 0; i <= listOfFiles.length; i++ ) {
file = listOfFiles[i].name;
%>

<% include fileName %>

<% } %>

blowsie commented May 30, 2014

+1

blowsie commented May 30, 2014

This also seems to be a popular question on stackoverflow.

cvince commented Jun 2, 2014

+1 --Thanks phplego and jasper-lyons

+1 Any chance of having this feature added?

+1

+1 Please merge

Any update please? I am also looking for the same solution.

Thank you jasper-lyons and phplego!
Working like a charm :) 👍

👍

Please merge - i would totally reduce my code!

tonmanna commented Aug 9, 2014

Not working for me.
I have a problem with options[name] is undefined.
I'm used ejs with Express 4.0 anyone have suggestion?
Thanks you

This is waiting for more than a year now, it would be great to have such basic feature!

Try Jade, it supports includes AND inheritance through blocks.

I've moved over.

Atinux commented Aug 18, 2014

If you use this solution, think to disable the view cache option in Express.js (true by default in production).

app.set('view cache', false); 

morwalz commented Aug 18, 2014

I cloned this fork. Still i am unable to make it work. it is said here it is work like <% include var_name %>

So i tried to use it this way <% include mytemp %>

It thorws error E:\node-examples\irobots\nodecontrolbot\express-dashboard\views\mytemp .ejs not found.

Is there spefic any to declare this?

Rikhart commented Aug 27, 2014

I am waiting for more than a year this feature is ready???

+1 very usefull funtionnality, i need it now, it will be nice if we can pass the name of the template as a variable and also some data.

+1 would be great

To note, I've added a simple test in the test cases for this and removed a jshint error occurring.

Does anyone have any further ideas on how this could be implemented safer / more semantically?

For example, with the implementation in my fork, a template including it's self will cause a stack overflow. How would this situation be managed? Remove variables used to resolve templates from the scope of the included templates? Prevent a template from including it's self?

In my experience with templating systems, small as it is, people seem to end up wanting templates to be as composable as functions though i believe that would require some serious changes.

+1

@ghost

ghost commented Dec 9, 2014

pretty please

+1
please merge

lklepner commented Jan 8, 2015

+1

Collaborator

mde commented Jan 8, 2015

Note that v2 of EJS implements include as a plain function call that does the include at runtime: https://github.com/mde/ejs#includes This lets you use whatever variable you want as the pathname.

lklepner commented Jan 9, 2015

Many thanks @mde - This is exactly what I was looking for.

wow, it's work 100%, good job.

This issue exists no more, one can use include as function just like @mde said (thanks by the way). So I think it would be good to close it, don't you think so @tj?

For anyone else who reaches this page, this is how it works:

<%- include(someVar, someObj) %>

Where someVar and someObj is defined, e.g., like this:

app.get('/', function(req, res) {
    res.render('template', {
        someVar: 'partials/index.ejs',
        someObj: {
            name: 'Bruno Krebs'
        }
    });
});

With these lines in you app, you would render template.ejs file and include partials/index.ejs on it. Oh, and partials/index.ejs would receive someObj variable to use it internally.

Collaborator

mde commented Jan 12, 2016

In fact, this entire repo is essentially closed. It's only here for historical reference.

Oh, I see, sorry.

If you want dynamic variable in ejs include statement ,just try this
<%- include(variable) %>

http://ejs.co/
Index

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <%- include('partials/title'); %>

http://localhost:3000/

Error: C:\WorkSpace\umbler\codeingnite-com-gitlab-branch-functionality-1jsRBAE2\app\views\login\login.ejs:6
    4|   <meta charset="utf-8">
    5|   <meta http-equiv="X-UA-Compatible" content="IE=edge">
 >> 6|   <%- include('partials/title'); %>
    7|   <!-- Tell the browser to be responsive to screen width -->
    8|   <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
    9|   <!-- Bootstrap 3.3.7 -->

server.js
app.use(express.static('./app/public'));

|--views
|---partials
|------title.ejs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment