Layout inheritance in jade - node.js

If you don't know what jade is.
I am having problem with the template inheritance system.My file structure is like so
/views/
|-- layout.jade
/products/
|-- index.jade
|-- product.jade
/static/
/stylesheets/
|-- style.css
The problems is that when loading the product page which receives an id as param (localhost:3000/product/:id if not for the /id it would load just fine), although the layout still extends correctly it does not load the stylesheet properly (the path is broken). I am doing half of it right though, in the index page of products the stylesheet loads just fine.
Layout.jade
head
link(rel='stylesheet', href='stylesheets/style.css')

It's probably the relative path in your href. Digging around the express documentation, I'm finding that the most popular approach is to reference the stylesheet from the base of the site like this (notice the / preceding stylesheets):
link(rel='stylesheet','/stylesheets/style.css')
This has the benefit of being easy, and working across routes of multiple depths (/about, /about/me, etc). However, it has the negative of not supporting app directory depth. For example, if you wanted to host your app at: http://yourserver/yourapps/yourapp this would be a problem. I don't know if you care about this or not, most of the examples for express certainly don't :-)
However, if you want to do this the right way, there is one example on the express github site: blog. https://github.com/visionmedia/express/tree/master/examples/blog
The approach here is to use a middleware component to grab the base url, and stuff it in the locals passed down to the layout view. Here's what your HTML would look like:
!!! 5
html
head
title Blog
link(rel='stylesheet', href=base + '/style.css')
body
#container!= body
The important parts to check out if you require this approach are middleware/locals.js, app.js where the middleware component is wired up, and layout.jade where the base href is used.
Happy Coding!

Related

Link href in a pug template

I am using pug as the view engine of a nodejs application. I have a layout that every other current view extends, that contains a navbar with links to common urls across the app.
For example, a link to the signin url would look like :
a(href='/auth/signin')`
This works fine from the root url ('/'), correctly leads to '/auth/signin'.
Within the '/auth' module which contains the routes for '/auth/signin', '/auth/signup' and '/auth/signout', the behavior is different. Instead, the route is concatenated with the current module's name. So for example, within the '/auth/signin' route, the link is actually a link to '/auth/auth/signin'. Clicking on it naturally leads to a 404, but on that page the link to signin is a link to '/auth/auth/auth/signin'.
And so on and so forth.
I don't fully understand what is going on here and how to prevent it. Is there away to link to my routes in absolute terms in pug without straight up typing the full url (which is unpractical for a variety of reasons), the same way you'd use a route helper in Ruby on Rails ?
Solution from the comments:
If you start your href's with a slash then these are interpreted as absolute url's. Then it does not matter in which folder your pug file is located. Please check that your href's start with / always.

Jade: modify <head> from any place other than the main page

Update:
I also posted this question to the Jade GitHub repository. I'm dropping it here too, for future (circular) reference:
https://github.com/jadejs/jade/issues/1943
Original post:
In a default node + express + jade application, I'm trying to build some common reusable components (menu, footer...) that I can include in some pages. I got stuck while trying to add references to .css or .js files from a block or an included file.
I want to do this because I don't want to include all the styles and scripts if I don't need them.
The folder structure is something like this:
Root
public
javascripts
main.js
menu.js
stylesheets
main.css
menu.css
views
shared
layout.jade
menu.jade
footer.jade
index.jade
The layout.jade file:
doctype html
html
head
title= title
link(rel="stylesheet", href="stylesheets/main.css")
script(src="javascripts/main.js")
body
block content
The index.jade file:
extends shared/layout
block content
h1= title
p Welcome to #{title}
In menu.jade there is some code that needs the menu.css and menu.js files.
Now I need a way to add those files to the <head> of the page only when I use the menu.jade file.
I started using Jade a few hours ago so it's very possible that I missed something in the documentation.
Thank you!
You could do this with jQuery in your menu.js like so:
$("head link[rel='stylesheet']").last().after("<link rel='stylesheet' href='stylesheets/menu.css' type='text/css'>");
I would caution you about this practice however. One alternative would be to have a build step that concatenates all of your CSS files together and serves all of your style in a single css file. LESS and cssmin are good options here, and they have nice modules to automate this for you in grunt or gulp, whichever you're using.
You did mention that you didn't want to include all styles if you don't need them, but I would suggest that having a web browser download many small css files is going to be slower than having it download one big one, especially if you serve those files via a webserver like nginx that employs gzip, or if you serve your static files through a CDN like CloudFront.

sails can't find layout.jade

I am starting to learn Sails (0.9.7, node 0.10.16) and running through the sailscasts episodes. I am also trying to use jade as I do so. Where I am stuck now is that sails is not finding views/layout.jade. I backed out all the jade stuff and redid with ejs and sails is not finding views/layout.ejs.
As a last resort, I cloned activtyoverlord (the sailscasts app) and when I sails lift activityoverlord does not find its views/layout.ejs.
Any suggests as to what I might be doing wrong?
I'm not a jade user, however, I think you need to put extends ../layout at the top of your index.jade file to use layout.jade.
Also, I think both the layout.jade and index.jade have tabs and spaces (I don't think you can use both). I took out the tabs and added spaces in your layout.ejs file.
I created a project from scratch, changed engine to jade in config/views.js but left layout to the default value.
Also, I used these tags in layout.jade:
// SCRIPTS
// SCRIPTS END
and
// STYLES
// STYLE END
Grunt then puts the appropriate paths for javascript and styles in your layout file. I couldn't get index.jade into the layout.jade but I don't know enough about jade to determine what's wrong.
Here's a link to the repo I made: https://github.com/irlnathan/sails-answers-jade

Show a partial without the layout.jade file

I'm using layout.jade as a template for all the partials. layout.jade includes a header, footer, sidebar etc, and the partials is what is shown in the body.
Now I've implemented a lightbox with iframe, to show one of the partials in. The problem is that I don't want the header, footer etc to be shown inside the lightbox, just the partial jade file.
Is there a way to exclude layout.jade in this case?
Thanks in advance!
Yes, here's how:
res.render('template', { layout: false /* ... other parameters */ });
See Express docs on view rendering. You can also specify a different layout.

How to provide the current route or view to the layout in ExpressJS?

I want to be able to dynamically reference JavaScript and Stylesheets depending on which page a user is on in Express. I thinking the best way to do so (though I'm open to suggestions) is to pass the current view to the layout page.
For example;
Given the url http://example.com/trees
I would want to have some logic in layout.jade that said something to the effect of:
script(src="/javascripts/{view}.js")
Which would get rendered as:
<script src="/javascripts/trees.js"></script>
Any suggestions or best practices for doing this?
req.route is the matched route, so things like req.route.path etc are available, or of course req.url which may be parsed. With express 2x you can expose these values to views automatically using "dynamic helpers" or res.local()
There are no best practices for doing this, since Express doesn't provide Rails like url helpers, so I think you're approach is fine.
The easy answer is to just put ALL your javascript into a single file and be done with it. Ditto for CSS. See the Ruby on Rails asset pipeline for details. You are probably making your life more complicated than necessary and also less efficient by having different javascripts on different pages.
However, since you asked, the answer for javascripts is easy. Just put the extra <script> tags in the view, not the layout. Problem solved. CSS doesn't work as cleanly because the <link> tags need to be inside the <head>. In this case, I define the styles I need as an array of strings and loop over that in my layout template. So in my route I set up a local variable such as
locals.css = ['/css/one.css', '/css/two.css']
Then just loop over that in your template and generate one <link> tag for each.

Resources