I use Node.js with Express and EJS Template and I want manage my HTML Templace dynamically..
For this time, I have :
- server.js
- views/
- - template.ejs
- - layout.ejs
In my server.js, i load the templates view, with data, and I use <% include %>
to load layout on the template :
server.js
var data = { some: 'stuff'};
res.render('template', data);
template.ejs
<% include layout %>
At this tine, the code work very good and I have the expected result.
But now, I want a variable on data, to say the filename of the layout, available on a layouts/ directory :
- server.js
- views/
- - template.ejs
- - layouts/
- - - home.ejs
- - - login.ejs
server.js
var data = {
layout_view: 'layouts/home'
};
res.render(template, data);
template.ejs
<% include layout_view %>
But, variable are not expored and only the name of the variable are tested, not the value :
Error: ENOENT, no such file or directory 'C:\\Users\\Arthur\\Desktop\\Node-www\\G\\views\\layout_view.ejs
How can load the view 'views/layouts/home.ejs' with the <% include %>
command and a variable ?!
Thank you all ! :)
Here's what I use for layouts in Express 4 (tested with ejs):
/*
Usage:
Set a global/default layout with:
app.set('view layout', 'bar');
Set a layout per-render (overrides global layout) with:
res.render('foo', { layout: 'bar' });
Or disable a layout if a global layout is set with:
res.render('foo', { layout: false });
If no layout is provided using either of the above methods,
then the view will be rendered as-is like normal.
Inside your layout, the variable `body` holds the rendered partial/child view.
Installation:
Call `mpResponse();` before doing `require('express');` in your application.
*/
function mpResponse() {
var expressResponse = require('express/lib/response'),
expressResRender = expressResponse.render;
expressResponse.render = function(view, options, fn) {
options = options || {};
var self = this,
req = this.req,
app = req.app,
layout,
cb;
// support callback function as second arg
if (typeof options === 'function')
fn = options, options = {};
// merge res.locals
options._locals = self.locals;
// default callback to respond
fn = fn || function(err, str) {
if (err) return req.next(err);
self.send(str);
};
if (typeof options.layout === 'string')
layout = options.layout;
else if (options.layout !== false
&& typeof app.get('view layout') === 'string')
layout = app.get('view layout');
if (layout) {
cb = function(err, str) {
if (err) return req.next(err);
options.body = str;
expressResRender.call(self, layout, options, fn);
};
} else
cb = fn;
// render
app.render(view, options, cb);
};
}
Resolved on comment by Ben Fortune :
Function not available yet on EJS, so update your files ejs.js and lib/ejs.js (ligne ~155)
Old 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');
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 = '';
}
New 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)
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);
include = read(path, 'utf8');
include = exports.parse(include, options); // Added transfer whole options
buf += "' + (function(){" + include + "})() + '";
js = '';
}
Sources
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.