I'm trying to use Jade to include variables from a content block into the larger page layout.
I want to put the the semantic content title for the page <title>
tag.
I'm using the excellent roots.cx toolkit to build a website in Jade and Stylus.
I have 2 files: pagelayout.jade
and page142.jade
.
The pagelayout
file contains a basic Jade page template (edited for simplicity):
!!!
html
head
title #{page.title} | My Great Site
body
!= content
The page142
file contains some unique content that will be included at the != content
:
- var page = { title: 'Page 142' }
h1 Content header of page 142
What I want the final HTML to look like:
<html><head><title>Page 142 | My Great Site</title></head>
<body><h1>Content header of page 142</h1></body></html>
At the moment, I get a compiler TypeError:
Cannot read property 'title' of undefined
I assume I get this error because the scope of Jade variables probably only works from template to content, not vice versa.
How can I pass page variables from content to page layout? All of the StackOverflow posts I've found only show variables going from page layout to content.
I saw that Jeff already answered this for you on Twitter, but for the sake of StackOverflow I will answer it for you again here.
Jade offers support for "blocks", that work similarly to includes, but allow you to pass blocks of Jade around. Think of blocks as "block-level includes" that are able to yield the content of a block of jade passed to it, just with a unique syntax.
In your layout.jade
, you can do this:
html
head
block head
title My Website
body
block content
And in your index.jade
, you can do this:
extends layout
block head
title A Specific Page of My Website
block content
p Hello World!
What will happen when you render index.jade
, is it will "see" that it extends layout.jade
(Line 1), and then see that it has block head
followed by some content, so it will search layout.jade
for block head
and replace the content it finds there with it's own.
Depending on how your Roots project is set up, this may or may not work. The current stable release of Roots provides it's own includes system to the default Roots template that is agnostic of any template engine.
This default Roots template is the one used by $ roots new projectname
.
I'm not sure if it is possible to overwrite the current template of a project, or if it is currently possible to change the way the template engine works (whether it uses the Roots include system or it's own) but what I do know is that the minimal Roots template, used with $ roots new projectname --min
will make the block includes work.
So, you can do one of two things here:
$ roots new <projectname> --min
FYI, Jeff and I both use --min
as our preferred template, with the exception that I have extended it to include assorted cross-browser polyfills.
EDIT:
Now, you might be wondering if replacing an entire block just to change the content of a tag somewhere in the block is a little inefficient - it is inefficient from a maintenance perspective - I cant really comment on processing speeds. But if you remember that in Jade, you can define variables, and that in Jade, you can put anything in a block - and you combine these two constructs - they become a lot more useful.
For example, if I know I'm going to use Jade extensively in a project, I will create a configuration.jade
file where I list all configuration/settings variables as a block. I will then include that file in my main layout (this just includes setting a title for the sake of simplicity):
config.jade
:
- var siteTitle = "My Cool Website";
layout.jade
:
block config
include config
html
head
title #{siteTitle}
body
block content
p Hello World
The reason we include
our config file instead of it just being defined at the top of a new layout is simply because some projects require more than one layout, so it makes sense to offload the responsibility of storing configuration variables to a different file so we can include
them in any layout we want. Notice, however, that we include
our config file inside a block config
. This allows us to replace that block with configuration variables inside our files, so - if perhaps I have a blog page, which I extend from layout
, I could write it like this:
blog.jade
extends layout
block config
- var siteTitle = "Blog - My Cool Website";
block content
each post in posts
p #{post.content}
See how much simpler that is? :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With