javascript - Struggle with EJS and scope of -not so- "local" variables - Stack Overflow

I'm wondering how I should write my node.js application, using EJS template.I'm actually loo

I'm wondering how I should write my node.js application, using EJS template. I'm actually looking for a proper way to define local variables with default values in a partial/template.

I'll exlain quickly of it works now:

When I call a template, like this:

<%- partial(__view.partialPath('tagPopover'), {
    title_popover: sentence.nickname,
    content_tag: '#' + sentence.nickname,
    icon_popover: ''
}) %>

I manage the default values this way, in the _tagPopover.ejs partial:

title_popover = typeof title_popover != 'undefined' ? title_popover : ''
classes_tag = typeof classes_tag != 'undefined' ? classes_tag : 'tags'
icon_popover = typeof icon_popover != 'undefined' ? icon_popover : false
content_tag = typeof content_tag != 'undefined' ? content_tag : ''

I don't use the var keyword, because it doesn't work at all, for instance, if I do:

var title_popover = typeof title_popover != 'undefined' ? title_popover : ''

Then EJS will interprate the var title_popover and create a local variable before to read the actual value of the variable title_popover. So I'll end up with a null, even if I actually sent a parameter...

When I discovered that, I decided to not use the var keyword... But I just recently discovered that all the variables that I create this way are actually global! Meaning that it's a really bad solution because I may likely end up rewriting global variables by loading a view!

I believe this will be a struggle later and I don't want my views to set/reset global variables by default (who would?!)

Do you have any solution for this? I thought about several already but I don't like any:

  1. Use the var keyword but also use a before pattern for local variable to avoid resetting parameters: var l_title_popover = typeof title_popover != 'undefined' ? title_popover : ''. This looks bad and confusing as hell.
  2. Use a namespace like view.title_popover = typeof title_popover != 'undefined' ? title_popover : ''. I want my variables to be locals, not globals, if I do so I will have something global that will exist in memory all the time.

How would you deal with that? I'm quite curious, maybe there is some EJS way to handle that or a helper, I don't know.

I'm wondering how I should write my node.js application, using EJS template. I'm actually looking for a proper way to define local variables with default values in a partial/template.

I'll exlain quickly of it works now:

When I call a template, like this:

<%- partial(__view.partialPath('tagPopover'), {
    title_popover: sentence.nickname,
    content_tag: '#' + sentence.nickname,
    icon_popover: 'http://placehold.it/64x64'
}) %>

I manage the default values this way, in the _tagPopover.ejs partial:

title_popover = typeof title_popover != 'undefined' ? title_popover : ''
classes_tag = typeof classes_tag != 'undefined' ? classes_tag : 'tags'
icon_popover = typeof icon_popover != 'undefined' ? icon_popover : false
content_tag = typeof content_tag != 'undefined' ? content_tag : ''

I don't use the var keyword, because it doesn't work at all, for instance, if I do:

var title_popover = typeof title_popover != 'undefined' ? title_popover : ''

Then EJS will interprate the var title_popover and create a local variable before to read the actual value of the variable title_popover. So I'll end up with a null, even if I actually sent a parameter...

When I discovered that, I decided to not use the var keyword... But I just recently discovered that all the variables that I create this way are actually global! Meaning that it's a really bad solution because I may likely end up rewriting global variables by loading a view!

I believe this will be a struggle later and I don't want my views to set/reset global variables by default (who would?!)

Do you have any solution for this? I thought about several already but I don't like any:

  1. Use the var keyword but also use a before pattern for local variable to avoid resetting parameters: var l_title_popover = typeof title_popover != 'undefined' ? title_popover : ''. This looks bad and confusing as hell.
  2. Use a namespace like view.title_popover = typeof title_popover != 'undefined' ? title_popover : ''. I want my variables to be locals, not globals, if I do so I will have something global that will exist in memory all the time.

How would you deal with that? I'm quite curious, maybe there is some EJS way to handle that or a helper, I don't know.

Share asked Mar 21, 2015 at 22:08 VadorequestVadorequest 18.1k27 gold badges129 silver badges231 bronze badges 4
  • can you please mark as accepted if this answers your question? – Justin Maat Commented Mar 26, 2015 at 13:37
  • I cannot reproduce. Yes, var does always create local variables, but they would be initialised with undefined. Not sure what you mean by "read the actual value", but inside the with they will definitely have the value that was passed by the object. And there's nothing where a null would e from. And no, even if you omit var, it will not create global variables as long as you use the same variable names that you did pass as object properties (classes_tag is missing in your example, though). – Bergi Commented Mar 29, 2015 at 15:37
  • 1 I don't send the classes_tag because I want to use the default one. But if I do that way then it creates a global variable. About the before to read, it means that somehow EJS initialize a new variable before to read the value of the variable, like that: var icon_popover = typeof icon_popover != 'undefined' ? icon_popover : false, it creates a new local icon_popover, before to read the icon_popover parameter I sent, then it tries to read it, but it's null, of course. I don't get what you mean by "but inside the with" though. – Vadorequest Commented Mar 29, 2015 at 16:51
  • I actually think the filters approach is the way to go, as it's the clearest to read and understand. Other templating libraries take similar approaches (see Liquid filters/tags with Ruby). – Justin Maat Commented Mar 30, 2015 at 14:36
Add a ment  | 

4 Answers 4

Reset to default 3 +50

There's a concept of filters in ejs. Also see adding-filters.

Basically I think you're looking for something similar to this.. Code below will set title_popover if exists in the res.locals, otherwise it sets to 'some default value'

<%=: locals | get:'title_popover','some default value' %>  

ejs.filters.get = function(obj, prop, default) {
  return obj[prop] === undefined ? default : obj[prop];
};  

I believe this is the easiest way to do it in ejs, but there might be some other methods. Looks like this actually being discussed on a github ticket :)

EDIT - This blog post seems to give some alternatives using the underscore library. Looks like they're wrapping the template in a layout somehow (I haven't fully grokked the article but it seems to make sense on the surface).

I've only used the above way however.

EJS is not a good template, as is to be expected because it's very old and inactive. That said, the templating engines for JS are not all that well-featured when it es to passing variables around. I am using Sails framework and what I do is simply pass the variables to the view in either my route settings (if they are hardcoded) or in my Controllers, if they are dynamic.

It is also possible to provide standard route settings to res.locals via policy.

For example I have the following settings in my sails routes:

  'GET /':{
    controller: 'IndexController.js',
    action: 'displayIndexPage',
    title: 'Main page',
  },
  'GET /flowchart': {
    controller: 'FlowchartController.js',
    action: 'displayFlowchart',
    title: 'Flowchart'
  }, //...

Then I have a policy viewToLocals.js with the following code:

module.exports = function(req, res, next) {
  res.locals.view = req.options.title;
  return next();
};

This, btw, will not override any data I pass to the view from controller or any other file. What I could do if I had your problem would be something like this:

//setPageParamsPolicy.js
module.exports = function(req, res, next) {
  res.locals.popovers = {
  title: ('undefined') ? res.get('body').username : 'Default title', //or wherever you fetch data from
  icon : ('undefined') ? res.get('body').avatar : 'www.site./defaultAvatar.jpg'
}
  return next();
};

Sails is built on Express, so maybe this information will be useful. Note however, that sails policies apply to controller actions, which means if you define a simple route to view, it won't apply - you have to route it to a particular controller instead. However you can put this object into the routes themseleves:

//routes.js
'GET /userpanel': {
    view: 'userpanel',
    locals = {
          popover: {
              title: ('undefined') ? res.get('body').username : 'Default title', //or wherever you fetch data from
              icon : ('undefined') ? res.get('body').avatar : 'www.site./defaultAvatar.jpg'
         }
    }
}

I have also wondered about this and came to the conclusion that there is no easy way to do this. But to me Sails provides a relatively straightforward solution that is also relatively foolproof.

EJS is an excellent templating language if you like using plain JS for things. The project is currently quite active.

The EJS module (now v2) on NPM is actively maintained here: https://github./mde/ejs. (The old v1 repo is no longer maintained.)

Landing site is here: http://ejs.co

Default values for data shouldn't be set in a template. Templates should only be used for rendering. A better approach would be to preprocess your data before passing it in:

var defaultVals = {
  foo: 'FOO',
  bar: 'BAR'
};
// Mix in left to right: https://gist.github./mde/81b131ff6810ed7c4e0e
var dataObj = mixin({}, defaultVals, {bar: 'NOT BAR'});
// Outputs "FOO, NOT BAR"
ejs.render('<%= [foo, bar].join(", "); %>', dataObj);

Incidentally, filters were removed from EJS in v2. They were a nonstandard feature that had nothing to do with embedded JavaScript, and are easy to replicate using your own code.

I defined default variables in ejs like this:

<%  var username, password%>
<script>
    var username = "<%= username %>",password = "<%= password %>" %>
</script>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744930409a4601700.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信