-
Notifications
You must be signed in to change notification settings - Fork 28
Using Blade with Meteor
Special thanks to mlohr for this wiki page.
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 slightly different approach. To the Blade smart package, each *.blade file is a template, except for the head.blade
template. This is often a source of confusion, so now that we cleared that up, let's get started...
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.
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 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.
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:
- Get the path of the *.blade file relative to your Meteor project directory
- If the file is stored in
views/
, removeviews/
from the name. If the file is stored inclient/views/
, removeclient/views/
from the name. - 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/client/views/foo/hello.blade
-->foo/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
template during the initial page load, placing the rendered content into the <head>
tag of the initial HTML document. head
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 within the head
template. 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"]
.
Just like the <body>
tags in Handlebars, the body.blade
template will be rendered after the initial page load, and its HTML will be directly inserted into the <body>
tag just before Meteor calls the Meteor.startup
routine.
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) );
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 Before Blade 3.0.0 stable, you could not place dynamic content here. Now you can!
p For example, `include` statements, view helpers, etc. work just fine in `body.blade` templates.
views/head.blade
title Blade is cool!
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. :)
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
foo.html
<template name="foo">
{{#each bars}}
{{> bar}}
{{/each}}
</template>
might look like this in Blade...
views/foo.blade
foreach bars as bar
include "bar" exposing bar
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.
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"})
The use of blocks are not recommended in Meteor for a few reasons. The limitation is this: If a parent template (let's call it parent.blade
) or any included template (let's call it include.blade
) contains a block declaration, any "reactive" features in include.blade
will be disabled.
Here's why this limitation exists...
A block is a marker in the template that tells Blade where more HTML can go. You then modify those blocks later in your template. You can even declare a block in a parent template and have it modified later in an included template.
Suppose, however, you put a block in an isolate region. Since the block can be modified elsewhere (possibly by an included template with its own data dependencies), it is very difficult (nearly impossible) to track the data dependencies of the block. And, therefore, if would be very difficult to track the data dependencies of the isolate
region containing the block. To explain this another way, Spark defines an isolate
region to be a section of a template that can be rendered separately from the rest of the template; that is, its HTML can be rendered by simply re-rendering that section of the template. However, if a block declaration is inserted into an isolate
block, Spark's definition of an isolate
region is violated. A block in Blade can be modified later in a separate section of the template, outside of the isolate
region.
This is a problem. So, to "solve" this problem, Blade turns off template reactivity if you try to put a block in an isolate
region. In fact, as mentioned before, Blade prevents you from having any "reactive" stuff in an included template that contains a block declaration. Even if the parent template contains a block declaration, "reactive" stuff for included templates is disabled.
-
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 inviews/...
and if your code tries to render a view, you end up with a problem. Your code will be loaded before your view templates (becauseclient/...
is loaded beforeviews/...
). 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 calledzCode
. 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 inMeteor.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
, orTemplate
) are not allowed inhead
templates. Helpers don't work either. This is by design, and it is not a bug. Handlebars also has this restriction.