ejs 2 custom delimiter - node.js

EJS2 can only do character to be use with angle brackets for open/close:
ejs.delimiter = '$';
ejs.render('<$= users.join(" | "); $>', {users: users});
I would like to use {{ }} instead of <% %>, previous version will allow this esj.open = '{{' and esj.close = '}}'.
Any help?

EJS has been updated & changed maintainers, so the main site is found here: https://ejs.co/
and the Github is here: https://github.com/mde/ejs
Unlike previous versions of EJS, you can't use completely custom delimiters now - you can use 'partial' custom delimiters - the first set of brackets aren't optional, but the following character is. To set up a custom delimiter you can do the following:
// app.js
const ejs = require('ejs');
ejs.delimiter = '?';
app.get('/', (req, res) => {
res.render('index', {
myVariable: 'Hey!'
});
});
// index.ejs
<div>
<p>
<?=myVariable ?>
</p>
</div>
// index.html (rendered output)
<div>
<p>
Hey!
</p>
</div>
You can add a complete options object and other things, but hopefully that gets you started if you want to change the default delimiters.

Documentation states that custom delimiters are supported:
https://github.com/tj/ejs#custom-delimiters

This isn't possible without modifying the module's source code.

My solution to using custom delimiters is be doing a string replace on the template
const template = fs.readFileSync(path.join(__dirname, './template.html'), 'utf8').replace('{{', '<%').replace('}}', '%>')
const render = ejs.compile(template)
This allows me to declare my template like this:
{{ if (someVar) { }}
{{= someVar }}
{{ } }}

Related

Cascading Template Use in mustache-express?

My intent is to define a page_layout template and a form template as well. Within the route handler i was going to parse the inner (form) template and inject into the greater layout than return.
After several plot twists i'm able to use the response.app to get access to my mustache template engine and parse a view, but the HTML is getting escaped :(
let router = require('express').Router();
let mustache = require('mustache');
router.get('/plant', function(request,response) {
response.app.render('plantForm', {pageTitle: "Plant"},function (err, html) {
response.render ('layout', { pageContent : html});
});
});
yields the outer template with escaped html where I expect content:
<div class="form-group">
<label for="plantNameInput">Plant Type</label>
Perhaps I'm misusing the technology?
From the Mustache documentation:
All variables are HTML escaped by default. If you want to return unescaped HTML, use the triple mustache: {{{name}}}.

Twig include with rerender

I want to include some template and append on button click (by js), and I need each included template to have a unique id.
Here is the logic where I appending the templates:
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`;
$('.table tbody').append(part);
});
Here is the how I generate uuid in the translationPart.twig
{% set uuid = uuid() %}
{{ uuid }}
The issue is that UUID is the same for all of the created templates. I understand why it's happening, it's b-z twig generated server-side and at the moment of generation it sees only one include. But is there some option to rerender included template for each new included copy? Or maybe some other way to set different UUIDs for each of the included templates.
Updated
uuid() is a custom twig function
$twig->addFunction(
new TwigFunction(
'uuid',
static function(): string {
return Uuid::uuid4()->toString();
}
)
);
You can achieve this via ajax calls, or string replacement.
String replacement
Twig template (translationPart.twig)
{% set uuid = '#_SOME_STRING_TO_REPLACE_#' %}
{{ uuid }}
Javascript
<button type="submit" id="addTranslationFields">Add translations</button>
// and js
$('#addTranslationFields').on('click', function (event) {
event.preventDefault();
event.stopPropagation();
let generatedUuid = generateUuidByJavascript();
let part = `{% include 'translationPart.twig' with {'languages': languages,}%}`.replace('#_SOME_STRING_TO_REPLACE_#', generatedUuid);
$('.table tbody').append(part);
});
Uuidjs can be used for generating uuid.

How do I use req.flash() with nunjucks?

I am using connect-flash to pass the flash message. In my controller, I am using the following code if (!req.user) {
req.flash("error_msg", "User not found !!");
return res.redirect(307, '/');
}
In my view, I tried
{{ error_message }}
{{ req.flash('error_message') }}
{{ req.flash.get('error_message') }}
But none of it works. What's the current syntax to parse the flash message in nunjucks ?
First of all you have to install "express-flash" and put below code in app.js
app.js
const flash = require('express-flash');
In Your Controller put below code when you want to pass message
req.flash('error_msg', "User not found !!");
return res.redirect(307, '/');
Put below code in your view file where you want to display message
<% if (typeof messages.error_msg !='undefined') { %>
<p class="error"><%= messages.error_msg %></p>
<% } %>
For anyone facing the same problem you can access the variable using {{ req.session.flash.error_msg }}
If you are using express js and nunjucks as template this is what I have done
in app.js
const flash = require('express-flash');
app.use(flash());
in Routes/controller code
try {
await User.deleteOne({_id:req.params._id}).exec()
req.flash("success_msg", "User deleted");
return res.redirect('/admin/users')
}
in Layout or view file
{% if messages.success_msg %}
<div class="alert alert-success" role="alert">
{{ messages.success_msg }}
</div>
{% endif %}
With connect-flash package, you cannot directly use req.flash in template engine. You need to add a middleware that adds the flash message to the res.locals which can be accessed in template rendering.
Here is a short code snippet.
// this part should be before all the request resolver.
// adding flash function to response locals
app.use((req,res,next)=>{
res.locals.flash = (arg) => { return req.flash(arg) };
next();
});
// request resolver
app.get("/",(req,res)=>{
req.flash("info","show me");
res.render("index.njk",{});
});
app.listen(8080,()=>{...})
In nunjucks file:
<h3>{{ flash("info") }}</h3>

Nodejs use method in view

For example,In my Nodejs app,I have a router:
exports.test=function(req,res){
res.render('./admin/test.jade',{html:[a,b,c]);
}
And I have Underscore.js
In my view test.jade:
-var _und=require('Underscore.js')
....
div
-_und.each(html,function(m))
span m
....
But I got error.This shows that,the Underscore.js is just be used as a server-side method,how can I use a server-side method in view?
You don't need to require underscore from a view. To view you should send just data (it means that in idea case you should not use underscore there at all). But if you would like, you can still send underscore like a function to view:
exports.test = function(req,res) {
res.render('./admin/test.jade',{ html: [a,b,c], _ : require("underscore") });
};
or like this:
exports.test = function(req,res) {
var underscore = require("underscore");
res.render('./admin/test.jade', { html : [a,b,c], _ : underscore });
}
After in your view you can access to that like this:
div
-_und.each(html,function(m))
span m
You can get inspired from my nodejs github markdown project (http://bit.ly/1aOAG35). There is used underscore for layouting and I'm using it as well in templates:
{{# onlyblogs.forEach(function(current){ }}
<li>
{{ current.title }}
{{# if (current.description){ }}
<span>{{ current.description }}</span>
{{# } }}
<span>{{ current.category }}</span> in <date>{{ current.date }}</date>.
</li>
{{# }); }}
Hope that it helped.

What is this character "" and why does it cause a line break?

I'm using handlebars + hbs (following the block/extend helper example) to render html for my node application. For some reason, one of my div's is getting pushed down 1 line.
I checked the dom inspector in chrome, and there's a line with double quotes:
Which causes this:
When I remove the double quotes from the dom inspector (press backspace or delete) the layout is correct:
What the crap is going on? Is it a non-printing character or something? There's nothing in the html/template, and a blank space (or whatever character that is) shouldn't cause a block level element to change position, right?
Here's some code:
The relevant section of Layout.html
<div id="details" class="east">{{{block "east"}}}</div>
The template:
<div id="details-title">
<h3 class="title elide" style="height:26px;">{{Title}}</h3>
</div>
<div id="details-body" class="content text">
<img class="card" src="{{ImagePath}}" />
<div>
<span class="type">{{Type}}</span>
</div>
<div class="body">
{{{Body}}}
</div>
</div>
The block + extend helpers: (from the hbs example)
hbs.registerHelper("extend", function (name, context) {
var block = blocks[name];
if (!block) {
block = blocks[name] = [];
}
if (typeof context.fn !== "undefined") {
block.push(context.fn(this));
}
});
hbs.registerHelper("block", function (name) {
var val = (blocks[name] || [])
.filter(function () { return true })
.join("\n");
// clear the block
blocks[name] = [];
return val;
});
Update
Apparently, this is char 65279, my precompiled handlebars templates all emit this as the first character when rendered.
So I added a hack to remove the BOM that appears as the first character in the template output:
var html = detailTemplate(res.data);
if (html.charCodeAt(0) === 65279) { // hack to fix precompiled hbs template bug
html = html.substring(1);
}
$("#details").html(html);
It turns out that the block + extend helpers have nothing to do with the problem. I'm assuming it's a problem with the encoding I'm using, but I'm not sure how to change that. The above code fixes the issue though.
Solved, Save with Encoding > UTF-8

Resources