Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing jade variables from content to page title?

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.

like image 605
hao_maike Avatar asked Jan 04 '14 01:01

hao_maike


1 Answers

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:

  1. Check with Jeff and see if it's possible to change the includes system over to Jade
  2. Or recreate the project using $ 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? :)

like image 115
razorbeard Avatar answered Oct 18 '22 23:10

razorbeard