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}}
Related
I'm new at node.js and i'm using handlebars(hbs), i have created a views and some partials, and everything goes well, but the problem is the rendered partials have unnecessary spaces which makes the page looks bad, here is my code :
handlebars view
{{>header}}
<h1>{{ title }}</h1>
{{>footer}}
handlebars partial (footer)
<footer>
Created By Hassan Ali
</footer>
and here is my app.js
const path = require("path")
const express = require("express")
const hbs = require("hbs")
const app = express()
// Folders Pathes
var publicFolder = path.join(__dirname, "../public")
var viewsFolder = path.join(__dirname, "../templates/pages")
var partialsFolder = path.join(__dirname, "../templates/components")
// Setting The View Engine
app.set('view engine', 'hbs')
// Setting The Views Directory
app.set('views', viewsFolder)
// Setting The Views Components
hbs.registerPartials(partialsFolder)
// Setting The Static Folder
app.use(express.static(publicFolder))
app.get("/notes", (req, res) => {
res.render("notes", {
title: "Notes App"
})
})
and when it's rendered i get some unnecessary spaces in the html before every partial with this &-#65279; entity (without - that after &)
<header>
Header Tag
</header>
<h1>Title of The Page</h1>
<footer>
Created By Hassan Ali
</footer>
any help will be appreciated.
EDIT: The problem is solved Thanks
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.
Is it possible in any way to use hogan.js as template engine with layouts something like
"Razor or master pages in .NET"?
I would get a result like this:
layout.hjs:
contains "header" & "footer"
and
index.hjs:
will include layout.hjs and contain only page content.
sure:
layout.hjs:
{{> header}}
{{$content}}
default content
{{/content}}
{{> footer}}
index.hjs:
{{<layout}}
{{$content}}
your content goes here
{{/content}}
{{/layout}}
see the hogan test file for all it can do:
https://github.com/twitter/hogan.js/blob/master/test/index.js
btw. this is Hogan#3.0.0, get it with a git url with mpn
I'm not sure what you mean, "Razor or master pages in .NET"? What are you looking to do, use view partials?
But the basic way of setting up Hogan.js for Express is as follows:
var express = require('express');
var app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'hjs');
app.use(app.router);
app.use(express.static( __dirname + '/public' ));
app.get('/', function( req, res, next ) {
res.render('index');
});
app.listen(3000);
You will have to npm install express [--save], npm install hjs [--save], depending if it's inside your package.json already or not.
Then you just make a views directory and throw an index.hjs file and you're set.
Let me know what you want to do with your templates and we can work from there.
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
I am trying to use express and render a layout.jade my directory tree is pretty standard.
├── apps
│ └── fridge_face
│ ├── routes.coffee
│ └── views
| └── index.jade
├── server.js
└── views
├── layout.jade
└── stylesheets
└── style.styl
In my routes.coffee when I render index.jade everything words fine, but layout is not rendered. I have tried moving layout into apps/fridge_face/views/ but that was not successful.
I have done no layout configuration.
Here is my
layout.jade
doctype 5
html
head
title 'What is up'
link(rel='stylesheet', href='/stylesheets/style.css')
body
!= body
routes.coffee
routes = (app) ->
app.get '/', (req, res) ->
Word.once 'wordsFetched', (params) ->
res.render "#{__dirname}/views/index",
layout: true
words: params.map (word) -> word.word
Word.getWords()
module.exports = routes
server.js config
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express['static'](__dirname + '/public'));
});
As you can see nothing that could or would make the layout not render... what am I doing wrong how do I get express to find my layout
Edit
I know I am making this question super long but adding some developments. First
When I remove the != from the layouts in both directories, nothing changes. My view is still rendered layout free.
When I add
app.set('view options', {
layout: false
});
and then explicitly render my layout in my view with either
layout: "#{__dirname}/views/layout"
# OR
layout: "layout"
# OR
layout: true
Nothing happens and the view is rendered layout free...
As someone above said, you're using version 3.0 which got rid of layout & partials & lets the templating engine handle that. Here's the answer via the migration wiki:
"To get back layout functionality with EJS you can use express-partials or ejs-locals."
(from https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x )
I ended up using express-partials & it worked exactly as it is in their example. I was unable to post the link to ejs-locals as I don't have enough reputation yet but you can find it on the wiki.
You are using outdated code with the new express version. Please see http://github.com/visionmedia/jade for the new usage of templating system.
Try explicitly specifying the path to your layout file when you call render. There's an example in the express docs:
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
My guess is there's different logic in express/jade depending on whether the view name is unqualified or specified as a filesystem path.
If layout doesn't work you can try with partial, I'm using ejs :
app.get('/', function(req,res){
res.render('layout.ejs', { layout:false,
locals : {
body: '../apps/index.ejs' ,
name : "Daniel"
}});
});
And in layout.ejs:
<html>
...
<%-partial(body)%>
<html>
In index.ejs :
<h1>Hola</h1>
<%=name%>