Express not finding/using layout - node.js

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%>

Related

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.

Using node and express to serve get(/foo/:bar) requests, when res.render(template), all relative links in template are relative to /foo instead of /

The offending route in my node server code is this:
app.get('/s/:searchTerm', function(req, res) {
res.render('index');
});
After this happens, all the relative links in index.jade are relative to "hostname/s/" instead of "hostname/", which is broken.
My node setup looks like this:
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public/'));
app.use(express.favicon(__dirname + '/public/img/favicon.ico'));
app.use(express.json());
app.use(app.router);
All of these routes, except for the /s/:searchTerm route, work. Even the /results route. There, the relative links in partials/result are relative to 'hostname' as I'd expect.
app.get('/', function(req, res) {
res.render('index');
});
app.get('/s/:searchTerm', function(req, res) {
res.render('index');
});
app.get('/results', function(req, res) {
res.render('partials/results');
});
index.jade simply references layout.jade:
extends layout
layout.jade begins like this:
!!! 5
html(lang='en' data-ng-app='FooApp')
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name='author', content='foo#gmail.com`')
link(rel='shortcut icon', href='img/favicon.ico')
title FooApp.com â„¢
// Bootstrap core CSS
link(href='//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css', rel='stylesheet')
// Custom css for this template
link(href='css/style.css', rel='stylesheet')
//if lt IE 9
script(src='https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js')
script(src='https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js')
body(data-ng-controller='SearchController'
.navbar.navbar-inverse.navbar-fixed-top(role='navigation')
.container
.navbar-header
button.navbar-toggle(type='button' data-target='.navbar-collapse'
How do I render a partial and keep links in that partial relative to 'hostname' ???
edit: added index.jade and layout.jade code
edit: ah, I see I'm doing something redundant with favicon
The behavior you are seeing is what is expected as hrefs are relative to the page that loads them. Since your /a/:searchTerm route is nested at /a, hrefs to static assets like img/favicon.ico will pick up their relative parent route. If you want the href to look in the root of your public directory for static assets, then prepend a / to the href like so: /img/favicon.ico

hogan.js with master pages or layouts

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.

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}}

Express Jade Layout Won't Render Even Though Layouts Is Set to True

I am new to Express for Node.js, and I was just setting up a simple app by following Pedro Teixeira's Node Tuts Episode 9. I wanted to experiment with layout files, so I set the layout to be "true." When I did that though, it didn't render with my layout, only with my body. How should I get it to render correctly? Below is my app.js file, my index.jade, my layout.jade, and a screenshot of my rendered page.
app.js
var express = require('express');
var app = express.createServer();
app.configure(function () {
app.use(express.logger();
});
app.set('views', __dirname + '/views');
app.set('view engine','jade');
app.set('view options', {layout: true});
app.get('/', function(request, response) {
response.render('index');
});
app.listen(4000);
index.jade
h2 Hello
p World!
layout.jade
!!! 5
html
head
title My template
body
#main
h1 Content goes here
p Testing 123
#container!= body
If you are using Express 3 this is normal the way template are rendered has changed.
Your layout needs to be like this:
!!! 5
html
head
title My template
body
#main
h1 Content goes here
p Testing 123
block content
And you templates:
extends layout
block content
h1 Something
Examples here:
https://github.com/dotcloud/express-on-dotcloud/blob/master/app/views/layout.jade#L64
https://github.com/dotcloud/express-on-dotcloud/blob/master/app/views/welcome.jade#L1
If you are starting with Node and Express feel free to clone this demo/tutorial App:
https://github.com/dotcloud/express-on-dotcloud
You can fool with it localy and discover some nice features of Express 3, if you want to share your app it is all setup to be pushed to dotCloud.

Resources