How to use partials in Express.js layout? - node.js

I have a layout.ejs file that contains my site's basic boilerplate HTML markup: doctype declaration, head, body, footer, the basics...
How would I go about placing the navigation in a separate partial file and including it into this layout? Is there a particular require() or include() function for doing this?
I am using EJS view engine.

Yes.
<% include path/to/template %>
Documentation here. https://github.com/visionmedia/ejs#includes

I came across similar issue with handlebars template, working with expressjs 4.0
In my app.js:
var hbs = require('hbs');
// register path to partials
hbs.registerPartials(__dirname + '/views/partials');
Then add a partial file to your partials dir:
/views/partials/nav.hbs
You could then call it within e.g index.hbs like so:
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
{{> nav}}
...
</body>
</html>

var hbs = require('express-handlebars');
// view engine setup
app.set('view engine', 'hbs');
app.engine( 'hbs', hbs( {
extname: 'hbs',
defaultView: 'default',
layoutsDir: __dirname + '/views/layouts/',
partialsDir: __dirname + '/views/partials/'
}));
see: page templates

Related

ejs include doesn't work with subfolders

I am using express and ejs to build a website:
"dependencies": {
"ejs": "^2.5.2",
"express": "^4.14.0",
in my app.js I have defined ejs as template engine and the root of views:
app.set('view engine', 'ejs'); // set view engine
app.set('views', 'app/views'); // set custom root for view engine
I then created my index.ejs file in which I included a partial from a subdirectory:
index.ejs
<head><% include ./partials/template/head %></head>
folder structure:
- views
index.ejs
-- partials
-- -- template
head.ejs
When a start the server, index is loaded without errors but without the head section.
If I change the include (pointing to a wrong location) the server fails to start highlighting the problem, so ejs is able to locate the head.ejs.
if I move head.ejs in the views directory the head is correctly loaded in the index.ejs.
So... I am a bit puzzled, it seems that in the subdirectory the file read but not loaded into the include.
After searching for around I tried using express-partials but it has not helped much.
Any clue?
Cheers, Giovanni
just change your include statement like this
<%- include("./partials/template/head.ejs") %>
this worked for me.
With Express 4.0
<%- include header.ejs %>
this worked for me.
I've never used an EJS template in <head> section.
I use ejs and express-ejs-layouts packages together.
So if you want to create a top division which would be fixed and appears on every different page (maybe a navigation part), you might create a main layout ejs for your application.
When I render an EJS on a route by using res.render('index'), rendered EJS page (index.ejs in my case) replace with <%- body %> parts in the example below.
And I use a navbar.ejs file with <% include navbar %> line. And the navbar is shown on the top of the page at every page, fixedly.
Example
app.js - needed variables, settings and middleware
var express = require('express')
var expressLayouts = require('express-ejs-layouts') // to use EJS layout
var app = express()
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(expressLayouts) // EJS Layout.ejs
layout.ejs file:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<% include navbar %>
<%- body %>
<% include page_footer %>
</body>
</html>
with express 4.0 using "ejs-mate module
In app.js
// Khởi tạo express
var express = require('express');
var app = express();
var engine = require('ejs-mate');
var port = process.env.PORT || 3000;
// Khởi tạo public, view engine...
app.use(express.static(__dirname + "/public"));
// Sử dụng đuôi html
var ejs = require("ejs");
app.set('view engine', 'ejs');
app.engine('ejs', engine);
// Cấu hình thư mục views
app.set("views", __dirname + '/views');
// Khởi tạo Web Server
var server = app.listen(port, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
app.get('/Admin', function (req, res) {
res.render('./admin/layout.ejs');
});
In layout.ejs
<html>
<head>
<%-partial('./sub-folder/header')%>
</head>
<body>
<-- -->
<h1>
buiducanh.net
</h1>
<%-partial('./sub-folder/footer')%>
</body>
</html>
I believe the problem to be not related to subfolders. If you look at your code:
<head><% include ./partials/template/head %></head>
We can see the include directive is used which will invoke the templating engine and return the html that you desire to render in your <head /> section of index.ejs.
However it doesn't get rendered simply because you forgot to include a "-", which tells it to actually print the contents into that section of html, you can also use a "=" which does the same thing only escaped.
So to fix you should edit your index.ejs as follows:
<head><%- include ./partials/template/head %></head>
Notice the inclusion of the "-" following the "<%".
Hope this helps.

Compiling Handlebars templates to html files

I'm working on a scaffolding project for simple, no cms, html sites. Basically, the site runs off a simple node server, running express & handlebars, with handlebars .hbs template files and a main.hbs as the main layout. This is all for development purposes. When the site is ready to be pushed up somewhere, I want a build task that will render it into a completely static html site.
My Problem: I can't figure out how to get the html of a fully rendered page, from my handlebars templates, loaded into a node module I can then create HTML files from using the module like a build task eg. node Build.js. Here is some code to show you, basically, the main layout and home layout need to be compiled then given to me as a js string.
PS. I have the regular handlebars package aswell, I'm just using express-handlebars for the server part.
server.js (irrelevant parts taken out)
// -----------------------------
// Dependancies
// -----------------------------
// https://www.npmjs.com/package/express
var express = require('express');
// https://www.npmjs.com/package/express-handlebars
var exphbs = require('express-handlebars');
// -----------------------------
// Template Engine
// -----------------------------
// Specify template engine & it's config
app.exp.engine('.hbs', exphbs({ extname: '.hbs', defaultLayout: 'main' }));
// Set the engine defined above
app.exp.set('view engine', '.hbs');
// -----------------------------
// Apply the routes to our application
// -----------------------------
app.exp.use(express.static(__dirname), app.router);
// -----------------------------
// Routes
// -----------------------------
// Home Route
app.router.get('/', getRoute);
// Route Controller
app.router.get('/:page', getRoute);
// Formats page data and renders the template
function getRoute(req, res) {
// If homepage, set some data
if(req.url === '/') req.params.page = 'home';
// Capitalize the route param for the page title
var title = req.params.page.substr(0,1).toUpperCase() + req.params.page.substr(1);
// Render the view
res.render(req.params.page, {
name: app.name,
title: title,
class: req.params.page
});
}
app.exp.listen(app.port);
Main layout (the standard html guts, the {{body}} data is where the template files are loaded into)
<!doctype html>
<html lang="en">
<head>
<title>{{title}} - {{name}}</title>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta charset="utf-8">
</head>
<body class="page-{{class}}">
<!-- Navigation -->
{{> nav}}
<!-- Page Content -->
<main>
{{{body}}}
</main>
</body>
</html>
And just for example, the home template
<div>
<p>
This is the homepage.
</p>
</div>

Node.js + Express + Handlebars.js + partial views

I am trying to make a simple HelloWorld project with Node.js|Express using Handlebars.js as a server template engine.
The problem is that I couldn't find any examples of using such chain, especially with multiple view.
For example I would like to define header view:
<header>
<span>Hello: {{username}}</span>
</header>
And use it in every page with other views.
Maybe I am thinking about this views in a wrong way, I thought that view is kind of control that I can reuse on any page inside any other view.
I appreciate any link to the tutorial or (much better) open source project that I can lear from.
I know this had been asked a long time ago, but no one has shown an answer in this post. So I will do so here. To ensure everyone is on the same page, I will be verbose in my answer. I apologize in advance if it seems overly simplistic.
In your server.js file (or app.js, wherever you defined handlebars as your view engine). Depending on what you are using as your npm package, such as hbs or express-handlebars etc. it may look different, but similar to this. Note: I'm using express-handlebars in this example.
file: server.js
...
var express = require( 'express'),
hbs = require( 'express-handlebars' ),
app = express();
...
app.engine( 'hbs', hbs( {
extname: 'hbs',
defaultLayout: 'main',
layoutsDir: __dirname + '/views/layouts/',
partialsDir: __dirname + '/views/partials/'
} ) );
app.set( 'view engine', 'hbs' );
...
and your file structure should look something like this:
| /views/
|--- /layouts/
|----- main.hbs
|--- /partials/
|----- header.hbs
|----- footer.hbs
|----- ... etc.
|--- index.hbs
| server.js
And your main.hbs file should look like this:
file: main.hbs
...
{{> header }}
...
<span> various other stuff </span>
...
{{> footer }}
To denote a partial you use this syntax: {{> partialsNames }}.
Using https://www.npmjs.org/package/hbs | https://github.com/donpark/hbs
Let's assume you have:
+ views
- index.hbs
+ partials
- footer.hbs
You need to register which folder contains your partials:
hbs.registerPartials(__dirname + '/views/partials');
The partials will have the exact name that the file has. You can also register specific names for your partials by using:
hbs.registerPartial('myFooter', fs.readFileSync(__dirname + '/views/partials/footer.hbs', 'utf8'));
Then you access it like this:
First example: {{> footer }}
Second example: {{> myFooter }}
Full example here: https://github.com/donpark/hbs/tree/master/examples/partial
I'm currently using ericf's implementation of "handlebars-express", and find it to be excellent:
https://github.com/ericf/express3-handlebars
The key thing to remember is that on express, as opposed to the within the browser, handlebars gets activated during the view render phase. The client code will end up being just plain HTML, as if you'd used mustache within a PHP context.
You need to use partials.
See https://github.com/donpark/hbs/tree/master/examples/partial for a good example of using partials.
Here's another example http://blog.teamtreehouse.com/handlebars-js-part-2-partials-and-helpers
If your current directory is something like this then,
| /public/
| /views/
|--- /layouts/
|----- main.hbs
|--- /partials/
|----- header.hbs
|----- footer.hbs
|----- sidebar.hbs
|--- index.hbs
| app.js
Then the structure of app.js will be
const express = require('express');
const app = express();
const port = 3001;
const path = require('path');
const handlebars = require('express-handlebars');
app.use(express.static(path.join(__dirname, 'public')));
app.set('view engine', '.hbs');
app.engine('.hbs', handlebars({
layoutsDir: __dirname + '/public/views/layouts',
defaultLayout: 'main',
extname: 'hbs',
//for partial directory
partialsDir : __dirname+'/public/views/partials',
}));
app.set('views', path.join(__dirname, '/public/views'));
app.get('/', (req, res) => {
res.render('index');
});
app.listen(port, () => console.log(`App listening to port ${port}`));
Set the main.hbs as follows
const express = require('express');
{{> header}}
{{> sidebar}}
<p>Your Content(static) or you can use {{{body}}} </p>
{{> footer}}

ejs include function can not find the template with html extension

My ejs engine set up is app.js is like below:
// this parse html file as ejs file
app.engine('.html', require('ejs').__express);
app.set('view engine', 'html');
app.set('views', __dirname + '/view');
My directory is like this:
view (folder)
home.html
head.html
app.js
Home.html is like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>home</title>
<% include head %>
</head>
<body>
</body>
</html>
and head.html is like this:
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="js/jquery-1.5.js"></script>
the problem is the file head.html will not be parsed if the extension was html. Error says it expect ejs file. So there is a problem with include function?
As Elie Gnrd is suggesting, you use .ejs files directly by changing the view engine configuration of Express.
If that isn't an option, and you want/need to keep using .html as an extension for your templates, you have to be explicit in the include:
<% include head.html %>
You can use .ejs files directly by using app.set('view engine', 'ejs'); and renaming index.html to index.ejs.
Here is an example:
http://robdodson.me/blog/2012/05/31/how-to-use-ejs-in-express/
arrr ;)
you did not mention what app - so I assume Express >=3
solution : forget the dot and __express in
app.engine('.html', require('ejs').__express);
It should read :
app.engine('html', require('ejs').renderFile);
change html file with ejs
-view
--home.ejs
--head.ejs
-app.js
set app view engine like
app.set('view engine', 'ejs');
make index.ejs for main file and include home.ejs and head.ejs in index.ejs
<%- include('head')%>;
<%- include('home')%>;
and render it app.js like
app.get('/', (req, res) => {
res.render('index');
});
cmiiw..
I too had this problem and modified this file of my app:
myapp/node_modules/ejs/lib/ejs.js
The function is:
function resolveInclude(name, filename) {
var path = join(dirname(filename), name);
var ext = extname(name);
if (!ext) path += '.ejs';
return path;
}
You can change the default extension or as in my case I changed the function to a more direct:
function resolveInclude(name, filename) {
return join(dirname(filename), name) + '.html';
}
They can modify the function as they wish.
I hope that is helpful.

Express & EJS - layout.ejs not used

Im trying out EJS as a view engine with Express. It seems that my layout.ejs is not used. I have two views index.ejs and layout.ejs both in my 'views' folder. It seems that index.js is rendered but layout.ejs is not. The layout.ejs file should be including a CSS file but when the page is rendered in the browser this is not there. Any test test text that I place in the layout.ejs file is not output with the response.
Am I missing an additional configuration step?
Thanks!
My server.js code:
var express = require('express');
var app = express();
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
res.render('index.ejs', {title: 'EJS Engine'});
});
app.listen(8080);
In my layout.ejs I am linking to a single css file which resides in the public folder.
layout.ejs:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<%- body %>
</body>
</html>
index.ejs
<div id="container">
index.html
</div>
Here's the module you need:
https://www.npmjs.org/package/express-ejs-layouts
Do the following:
npm install express-ejs-layouts // install the layout module from the command line
var express = require("express")
,path = require('path')
,fs = require('fs')
,expressLayouts=require("express-ejs-layouts") // add this requirement
, app = express();
app.use(express.bodyParser());
app.use(expressLayouts); // add this use()
app.use(express.static(__dirname));
Now the ejs engine should use your layout.
app.set('view options', { layout:'layout.ejs' });
Place layout.ejs into your views folder.
Alternately you can place layout.ejs into views/layouts folder and then use
app.set('view options', { layout:'layouts/layout.ejs' });
I have a similar issue. In my case I would rather use Jade but I have a requirement for a more "html" style template engine for a particular project. At first I considered express-partials or ejs-locals (as mentioned in a comment by Jonathan Lonowski) or even using html via the pipe or dot syntax within Jade templates (see here for more information about that option and this SO post). I am not able to introduce the additional dependencies for express-partials and ejs-locals into this project. These two projects do look good and might meet your needs.
If you do not want to use these projects, you can do something like the following:
views/layout-head.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>The title</title>
</head>
<body>
views/layout-foot.ejs
</body>
</html>
views/index.ejs (or any other page)
<% include layout-head %>
This is the index page - <%= title %>
<% include layout-foot %>
routes/index.js
exports.index = function(req, res){
res.render('index', { title: 'Express' });
}
This is not an optimal solution but it works. Most of my application will be a single page app and I have some other restrictions I have to work within so this works for my needs. This may not the best solution in many cases - especially if you have complex and/or changing layouts.

Resources