changing type of code wrapper for express + node.js + ejs - node.js

In client side ejs I use [% code %] instead of <% code %> to mark ejs code, but I would like to do the same on the server side with express. On the client side I would do something like var template = new EJS({text: template_src, type:'['});
Here is my node code:
app.set('view engine', 'ejs');
app.register('.html', require('ejs'));
app.get('/', function(req, res){
res.render('index.html', { title: 'My Site' });
});
Where do you set the "type" paramater so I can change this option

From the EJS github page:
Custom tags can also be applied globally:
var ejs = require('ejs'); ejs.open = '{{'; ejs.close = '}}';
The only thing you need to do it copy these lines at the beginning of your Express app and that's that - the change is applied globally (change the open and close tag to whatever you want).
Update for most recent version as of July 20, 2016
As of most recent versions of EJS, it is not possible to use custom tags anymore (see https://github.com/mde/ejs/issues/55 ). All you can do is change delimiters from default % to others ( delimiter option ).
There are talks about re-enabling this. See https://github.com/mde/ejs/issues/88 and https://github.com/mde/ejs/issues/115

If you use express:
app.set('view options', {
open: '{{',
close: '}}'
});

ejs v2.* use a different option:
var ejs = require('ejs'),
users = ['geddy', 'neil', 'alex'];
// Just one template
ejs.render('<?= users.join(" | "); ?>', {users: users},
{delimiter: '?'});
// => 'geddy | neil | alex'
// Or globally
ejs.delimiter = '$';
ejs.render('<$= users.join(" | "); $>', {users: users});
// => 'geddy | neil | alex'
You can't replace the < and > character.

Related

How do you send an object to a helper in Handlebars?

Learning handlebars and Express I'm trying to learn of a way to send an object without always having to build in the render. For example if I have:
const details = {
version: process.env.npm_package_version,
author: 'foobar'
}
I can send this to my footer.hbs in partials from:
app.get('/', (req, res) => {
res.render('index', {
details
})
})
but looking for a way to send it to a template file and not always in a render I've read in the documentation about block helpers and tried:
// Define paths for Express config
const publicDir = path.join(__dirname, '../public')
const viewsPath = path.join(__dirname, '../templates/views')
const partialsPath = path.join(__dirname, '../templates/partials')
// Setup hbs engine and views location
app.set('view engine', 'hbs')
app.set('views', viewsPath)
hbs.registerPartials(partialsPath)
hbs.registerHelper('appDetails', () => {
const details = {
version: process.env.npm_package_version,
author: 'foobar'
}
return details
})
but in my directory /partials from file footer.hbs I try to use the helper:
<footer>
<p>Created by {{details.author}} | version: {{details.version}}</p>
</footer>
and it doesn't work. I've searched the site and I've read:
How to set a variable for the main handlebars layout without passing it to every route?
nodejs + HBS (handlebars) : passing data to partials
Passing variables through handlebars partial
In my Node and Express app is there a way to send data to the partials file without having to always send it in render?
There are two ways a Handlebars Helper can add data to the rendering context of a template:
1) By directly mutating the template's context or 2) By using private variables
Example: https://codepen.io/weft_digital/pen/JjPZwvQ
The following helper updates or adds the data points name and newData to the template's global context, and it also passes a private variable, using the data option.
Handlebars.registerHelper('datainjection', function(context, options) {
this.name = "Bob";
this.newData = "Updated"
return context.fn(this, { data: {private:"pirate"} });
});
Before you call the {{#datainjection}}{{/datainjection}} block in your template, {{name}} will be set to whatever value you pass to the render function, but every occurrence of {{name}} within or after the {{#datainjection}}{{/datainjection}} block will use the updated value, which is "Bob" in this case.
The private variable we are passing can only be accessed within the {{#datainjection}}{{/datainjection}} block using the "#" decorator.
For example:
{{#datainjection}}{{#private}}{{/datainjection}}
will render the string "pirate"

pug : TypeError: View is not a constructor

I'm trying to make a website using NodeJS with express and pug for templates.
I integrated Pug using the express docs, but I keep getting TypeError: View is not a constructor on the render function. I really looked, but the only people who had this problem got it with other templates, and were not doing it has simple.
So at the end I did it like this :
var express = require('express');
var server = express();
server.set('views', './views');
server.set('view engine', 'pug');
server.get('/', (req, res) => {
res.render('example', {title: "code", message: "message"});
});
require('./settings')(server); console.log('Settings initialized');
server.listen(server.settings.port);
console.log('Server listening on port', server.settings.port);
And in views/ the template looks like :
html
head
title = title
body
h1 = message
In package.json, I imported it like : "pug": "^2.0.0-rc.1"
Thank you for your tips ! And have a nice day.
-- EDIT --
So I made a little experiment by uninstalling pug ... I have the same result, so I guess I didn't install or parametrized well pug.
-- EDIT --
Made some other tests and it turns out without the require it works well. But I don't see why, and I need to import external files.
This could be happen for various reason one of the most frequent is that there is a typo in the way you use pug in your index.js or where the object is instanced.
After made sure to have installed it locally( check your package.json) and to have created a root a folder called "views", and in there same file that you use in your rooter, then to be sure to use the sintax:
server.set('view engine', 'pug');
server.set('views','./views');// default, but if you specify don't make mistake on this
In your case I believe it is the order that caused this error.
Another note, useful is that the pug sintax, is required that "tags" are followed without space by "=", like:
html
head
title= title
body
h1= message
I had the same error because of a typo in views
server.set('view', './views');
server.set('view engine', 'pug');
I fixed it by putting an s to views
server.set('views', './views');
(this discussion assumes app is express: var app = express();)
You're getting this error because you're stepping on app.settings, which contains a view property.
I understand the appeal of wanting to call app.settings, so you can use app.settings.custom instead, and it won't cause a clash:
settings.ts
module.exports = {
port: 3000
}
app.ts
// settings
app.settings.custom = require('./settings')
...
var server = await app.listen(app.settings.custom.port, async () => {
var address = server.address()
console.log(`app.js - server started at ${new Date().toLocaleTimeString()} in ${app.environment} - http://${address.address}:${address.port}`)
})
If you don't like .custom, you can use Object.assign(app.settings, mySettings), just make sure no property values clash.

Load templates from existing file

I'm using Handlebars in my NodeJS application as my templating engine.
I've put all my templates in a views folder like so :
-
- /controllers
- /views
- index.html
- server.js
Here's my code to render the template when the user access a given URL (using express for routing) :
app.get("/", function(req, res){
var template = handlebars.compile("views/index.html");
var data = {"name": "Charles"};
var result = template(data);
res.send(result);
});
I'm trying to render a template from a file, but it's not working. This is what the browser outputs directly when I'm accessing the / URL :
views/index.html
That makes sense, since it's interpreting the given param as a string directly and not as a path to an external template.
How can I load my template file (in this case the one in views/index.html to a variable, so that I can then render the template?
The only examples I found were storing all the templates in a file and loading them via AJAX, but all these examples were from "front-end" handlebars and not when using it with Node.
Is it possible to achieve what I want? I looked at the documentation but it's hard to find good infos for handlebars with NodeJS.
From your description, it sounds like you want handlebars as view engine, with dynamic views. You don't need to do this manually, here is an example (using express-handlebars):
var handlebars = require('express-handlebars');
app.engine('.html', handlebars({layout: false, extname: '.html'}));
app.set('view engine', '.html');
app.get("/:view", function(req, res){
var view = req.params.view;
res.render(view, { "name": "Charles" }); // Whatever data you want
});
With handlebars you have to load the file yourself or you can precompile the files (using grunt/gulp maybe) I feel way more confortable with swig ( http://paularmstrong.github.io/swig/ )
It is very simple to use. And it has also integration with express if you want.
var swig = require('swig');
swig.renderFile('/path/to/template.html', {
pagename: 'awesome people',
authors: ['Paul', 'Jim', 'Jane']
});
In your case
app.get("/", function(req, res){
res.send(swig.renderFile('views/index.html', {"name": "Charles"}));
});

Jade template inheritance without Express

I would like to use Jade block inheritance but I'm not sure how to do that if I'm not using Express. According to the Jade doc, I can use block inheritance in Express by simply adding app.set('view options', { layout: false });. How can I achieve this without Express?
https://github.com/visionmedia/jade
You don't need Express at all to use Jade's Template inheritance; you only need Jade:
// app.js
var jade = require('jade');
var options = { pretty: true, locals: {} };
jade.renderFile(__dirname + '/home.jade', options, function (err, html) {
console.log(html);
});
// home.jade
extends core
block body
h1 Home
// core.jade
doctype html
html
head
meta(charset='utf-8')
title Foo
body
block body
Another example can be found in the repository:
examples/extend.js
examples/extend.jade
examples/extend-layout.jade.
The reason the Jade docs mention setting the 'view options' for Express 2.x is because Express' own (and now defunct in 3.x) layouts are a competing feature that should be disabled to prevent conflicts when using Jade's inheritance.

Express - Passing data to all routes

Hi is there a 'express' specific way to make some global app data available to all my routes?
Or is it a case of just using an module.exports statement?
Any pointers more than welcome.
Node noob - btw
You can set a global object that is also available in your layout
app.js
app.configure(function(){
app.set('view options', {pageTitle: ''});
});
app.get('/',function(request, response){
response.app.settings['view options'].pageTitle = 'Hello World';
response.render('home');
});
layout.jade
!!!
html
head
title= pageTitle
body!= body
You can use app.set() in the setup portion of your app to make it available to each request. The app object is available via req.app in your routes.
Personally, I like to do an app.set('name', obj); in the setup and in the routes I access it via req.app.settings.name.
You could also use a dynamic helper to pass data to all views.
app.js
// Dynamic Helpers
app.dynamicHelpers({
appSettings: function(req, res){
return {name:"My App", version:"0.1"};
}
});
Now on your views you can use it like this (I used ejs on this example but it should work with jade or any other view engine):
view.ejs
<%= appSettings.name %>
<%= appSettings.version %>
Hope this helps.

Resources