Skip to content

Using Blade with Meteor

bminer edited this page Mar 7, 2013 · 91 revisions

Special thanks to mlohr for this wiki page.

HEADS UP! Using Blade with Meteor has changed! We strongly recommend that you migrate to Blade version 3.0 or higher and follow the new instructions listed below.

Blade vs. Handlebars

The Blade smart package takes a slightly different approach from the Handlebars package. In Handlebars, you can define files, and within files are various tags: head, body, and the special template tag. You can have <body> tags in multiple files, and the content is concatenated and served with the initial page load. Also, any content in a <template> tag is stored as an HTML template.

Blade takes a different approach. To the Blade smart package, each *.blade file is a template, except for the head.blade and body.blade templates. This is often a source of confusion, so now that we cleared that up, let's get started...

Adding Blade to your Meteor project

At the time of this writing, Blade is not a part of the Meteor core smart package list. You can, however, add Blade to your project by installing Meteorite and adding the Blade Atmosphere project.

Adding Blade the Meteorite way

You can install the Atmosphere smart package using Meteorite. Information on using and installing Meteorite can be found here. Once Meteorite is installed, execute this command from your Meteor project directory:

mrt add blade

The old way

The old way to add Blade to your project is to symlink the Blade smart package directory into your Meteor packages directory like this:

ln -s /path/to/.../blade/meteor /path/to/.../meteor/packages/blade

In Debian/Ubuntu, the command is this:

ln -s /usr/lib/node_modules/blade/meteor /usr/lib/meteor/packages/blade

Then, execute meteor add blade in your Meteor project directory.

See Blade's README file for more information.

Getting Started

Within your Meteor project directory, I strongly recommend that you create a views/ directory for your Blade templates. You can place *.blade files anywhere in your project directory, but you may run into issues when you include a file that is stored outside of the views/ directory.

The name of your Blade template will be generated based upon its location within your Meteor project directory. The template name is generated as follows:

  1. Get the path of the *.blade file relative to your Meteor project directory
  2. If the file is stored in views/, remove views/ from the name. If the file is stored in client/views/, remove client/views/ from the name.
  3. Remove the .blade file extension from the name

Examples:

  • /home/you/meteor_project/hello.blade --> hello
  • /home/you/meteor_project/views/hello.blade --> hello (Note: watch out for namespacing issues)
  • /home/you/meteor_project/foo/bar/world.blade --> foo/bar/world

The Blade smart package renders the head and body templates during the initial page load, placing the rendered content into the initial HTML document. head and body templates may not contain references to Session, Meteor, or Template, as these variables are not available until after the initial page load. Similarly, helpers do not work with head and body templates. You can always load another template at runtime if you want your initial page to contain dynamic content. All Blade files/templates will be defined under the Template global variable, as normal. That is, a template in ./views/foo/bar.blade is accessable via Template["foo/bar"].

Example of a regular template:

Create templates in your views/ directory:

views/test.blade

h1 This is only a test
h2 Cool!
input(type="button" value="Click Me")

You can render that template from another Blade file by using include:

views/homepage.blade

#container
  include 'test'

(This is equivalent to the Handlebars syntax {{> test}}.) You can also access your templates programatically through Meteor's Template object. Template.test() should output

<h1>This is only a test</h1><h2>Cool!</h2><input type="button" value="Click Me"/>

With jQuery, you could render the template like this:

$("body").append(Meteor.render(Template.test) );

Example of body and head templates:

views/body.blade

h1 Hello world!
p The content contained with this file will be placed into the <body> tag of the initial HTML document
p You can't put any dynamic content here, though... just static HTML.
    | Therefore, the use of body.blade templates is somewhat discouraged.

views/head.blade

title Blade is cool!

References to helpers or global variables (like Session or Meteor) are not allowed in head or body templates:

views/body.blade

h1 Hello world!
//-The following line will cause your application to fail when it starts up
p Welcome, #{Session.get("name")}

Example using isolates

views/question.blade

isolate
  - console.log("Render name")
  h1 Hey, I have a question for you, #{Session.get("name")}.
isolate
  - console.log("Render question")
  p.question= Session.get("question")

Each isolate will be rendered separately. Check the console if you wish. :)

Converting a Handlebars template to Blade

The following Handlebars template can be converted to Blade quite easily...

foo.html

<template name="foo">
 {{#each bars}}
   <p>{{bar}}</p>
 {{/each}}
</template>

might look like this in Blade...

views/foo.blade

foreach bars as bar
  p=bar

Binding events

Just like in Handlebars, you can call the events function of a template and pass an event map. The this argument to the event handler will be the data context of the element that triggered the event (in Blade, at the time of this writing, the data context is the Object passed to the Template during rendering).

Inline event bindings also work with Meteor.

Using Blade and Handlebars in your Meteor Project

You can use a mix of Handlebars templates and Blade templates, although you should be aware that the syntax for including templates or partials will likely be incompatible. To include a Handlebars template into Blade, access the Template global variable. For example, to "include" the Handlebars template foobar, you can't simply write include "foobar" in your Blade template, since "foobar" is not a Blade template. Instead, this one-liner should do:

!= Template.foobar({"optional_data_object":"goes here"})

Troubleshooting and Known Issues

  • Element preservation has not been fully tested, and I don't really know how well it works for included templates (see issue #116). Please feel free to post more information on this wiki page or create an issue if you run into bugs.
  • Meteor does not necessarily load compiled Blade templates before your application code. By default, Meteor loads and bundles source files alphabetically. So, if you put some JavaScript code in client/index.js and your views in views/... and if your code tries to render a view, you end up with a problem. Your code will be loaded before your view templates (because client/... is loaded before views/...). This bug doesn't happen in Handlebars because of a hack in app/lib/packages.js. Obviously, a workaround for this is to put your code in a folder called zCode. Since it starts with the letter z, it will be loaded last. Plus, it makes you sound more French? See Meteor issue #181 Alternatively, if you wrap your code in Meteor.startup calls, this problem can also be avoided.
  • The Blade smart package cannot minify compiled templates. Meteor issue #180
  • References to global variables (like Session, Meteor, or Template) are not allowed in head or body templates. Helpers don't work either. This is by design, and it is not a bug. In Handlebars, you could use Session or Meteor within a <body> tag, but not a <head> tag. I didn't like the Handlebars implementation, so you're stuck with this one for now. If you don't like it, write to me and complain. :) The body.blade template is mostly for static content (i.e. a loading page or whatever). Once your application is loaded, you can do $("body").replaceWith(Meteor.ui.render(Template.homepage) ); from your application code. It's one extra line of JavaScript.