Skip to content


Subversion checkout URL

You can clone with
Download ZIP


When a namespace is specified, register partials in that namespace #33

wants to merge 1 commit into from

4 participants


A namespace is specified for many reasons, most involving the idea of being able to dynamically look up templates at runtime. There are cases where it becomes important to also have access to partials using the same mechanism that’s used for templates.

This PR modifies the registerPartial() call to additionally add a reference to the partial in the provided namespace. If no namespace is provided then the registerPartial() call is unmodified.


Thanks for taking the time to put this PR together Phil!

I've never seen this pattern before, and I think it might muck up the current use case for namespaces and partials.

/cc @tbranyen / @mehcode / @thanpolas / @phawk can I get some more eyes on this?


@pdokas reasoning makes sense.

However for production optimization reasons i'd like to see that feature only enabled explicitly by setting a debug switch to true in the task's configuration.


This isn't going to break any of the current implementations so long as a partials file name doesn't conflict with a templates filename, could become quite difficult to debug if it does.

Would be nice to prefix the partial filename with something to ensure this doesn't happen. 'partial_'+... or something similar/

Other than that I'm happy enough with it.


I spoke with my team member who originally proposed this solution and he presented a good example use for this.

Let’s say you have a single page app where the History API is used to dynamically provide links to states. These URLs can be directly requested, resulting in server-generated page loads.

So on this site you have a page which has a link that opens a modal dialog with the page's metadata in it. This updates the URL from to Essentially what happens here is a metadata partial is rendered into the modal dialog.

Now when this URL is bookmarked or shared, what happens in our setup is the server renders a page. And in this setup, instead of rendering the normal /posts/123 page and then somehow directing the client-side end of things to automatically trigger the JS modal dialog state, instead it renders the metadata partial as a full page.

To achieve this deep-linking trick a low-cost engineering solution is to register partials in the standard registerPartial() way, but also to hang them off your custom namespace where your usage patterns are up to the developers. It is this pattern that this PR addresses.


@pdokas would you discuss the option to have the modal rendered as a normal view instead of a partial?

It sounds like the normal view role is more fitting for this case.


@thanpolas I’m sorry, could you explain what you mean by “normal view”?

Also, I think your idea of a debug flag could also work. Perhaps it could be something along the lines of an option called partialsUseNamespace which is a boolean, or even partialsNamespace which is a string and could be used to avoid the collision possibility @phawk mentioned. Either of those would be fine in my eyes.


@pdokas the contents of the modal when route /posts/123/meta/ is viewed, should be a handlebars template and not a partial is what i'm suggesting.


@thanpolas I agree, and in essence that’s what this PR is all about :grinning:

The reason why a partial is the better choice is because its predominant use case is as a transient bit of DOM that’s dynamically loaded and later discarded in the client.

However, when a route is entered that triggers server-side page generation where this partial provides the entirety of the DOM it makes a lot of sense from a DRY perspective to treat the partial as a proper template and render it directly instead of creating an all-new template that consists of:

{{> metadata}}

I think I failed to explain... my idea was to have no partial in the mix whatsoever.

Nevertheless, if you judge that a partial is the way to go and you need to treat it as a partial on the front and as a template in the back then that's an operational requirement and not a debug one.

I still think this should be optional, so the explicit declaration for the switch needs to change from debug to something more fitting... partials_with_namespaces ?


@thanpolas I agree, do you have a preference between the boolean and string options I suggested four comments back?

The idea being that instead of checking for the presence of the current namespace option before adding partials to the namespace, that we’d either…

  1. if partialsUseNamespace is set to true, add partials to namespace
  2. if partialsNamespace is provided, add partials to it

I vote for the boolean value.

Namespace collisions between templates and partials should be the responsibility of the developer, to the effect that he / she chooses a proper naming convention.

@tkellen, @tbranyen ball is in your hands


I’m personally ok with both options. I agree that collisions are a developer responsibility in the same vein as inadvertent variable shadowing.


I vote for the boolean value also. Let's do that and get this puppy deployed.


Excellent, I'll get a commit in later today.


Hey Phil, would you mind rebasing these into a single commit? I'll merge and publish right away after.


All set!

@tkellen tkellen closed this pull request from a commit
@pdokas pdokas If a new option, partialsUseNamespace, is set to true then add partia…
…ls to the namespace set in `namespace`.

Closes gh-33.
@tkellen tkellen closed this in f7b1733
@pdokas pdokas deleted the pdokas:partials-namespace branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 27, 2013
  1. @pdokas

    If a new option, partialsUseNamespace, is set to true then add partia…

    pdokas authored
    …ls to the namespace set in `namespace`.
This page is out of date. Refresh to see the latest.
8 Gruntfile.js
@@ -152,6 +152,14 @@ module.exports = function(grunt) {
files: {
'tmp/partial_regex.js': ['test/fixtures/par_partial.hbs', 'test/fixtures/one.hbs']
+ },
+ partials_use_namespace: {
+ options: {
+ partialsUseNamespace: true
+ },
+ files: {
+ 'tmp/partials_use_namespace.js': ['test/fixtures/_partial.hbs', 'test/fixtures/one.hbs']
+ }
// Unit tests.
6 docs/
@@ -19,6 +19,12 @@ options: {
+## partialsUseNamespace
+Type: `Boolean`
+Default: 'false'
+When set to `true`, partials will be registered in the `namespace` in addition to templates.
## wrapped
Type: `Boolean`
Default: `false`
8 tasks/handlebars.js
@@ -35,7 +35,7 @@ module.exports = function(grunt) {
grunt.verbose.writeflags(options, 'Options');
var nsInfo;
- if(options.namespace !== false){
+ if (options.namespace !== false) {
nsInfo = helpers.getNamespaceDeclaration(options.namespace);
@@ -83,7 +83,11 @@ module.exports = function(grunt) {
// register partial or add template to namespace
if (isPartial.test(_.last(filepath.split('/')))) {
filename = processPartialName(filepath);
- partials.push('Handlebars.registerPartial('+JSON.stringify(filename)+', '+compiled+');');
+ if (options.partialsUseNamespace === true) {
+ partials.push('Handlebars.registerPartial('+JSON.stringify(filename)+', '+nsInfo.namespace+'['+JSON.stringify(filename)+'] = '+compiled+');');
+ } else {
+ partials.push('Handlebars.registerPartial('+JSON.stringify(filename)+', '+compiled+');');
+ }
} else {
filename = processName(filepath);
if (options.namespace !== false) {
27 test/expected/partials_use_namespace.js
@@ -0,0 +1,27 @@
+this["JST"] = this["JST"] || {};
+Handlebars.registerPartial("partial", this["JST"]["partial"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
+ this.compilerInfo = [2,'>= 1.0.0-rc.3'];
+helpers = helpers || Handlebars.helpers; data = data || {};
+ return "<span>Canada</span>";
+ }));
+this["JST"]["test/fixtures/one.hbs"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
+ this.compilerInfo = [2,'>= 1.0.0-rc.3'];
+helpers = helpers || Handlebars.helpers; partials = partials || Handlebars.partials; data = data || {};
+ var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this;
+ buffer += "<p>Hello, my name is ";
+ if (stack1 = { stack1 =, {hash:{},data:data}); }
+ else { stack1 =; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + ". I live in ";
+ stack1 = self.invokePartial(partials.partial, 'partial', depth0, helpers, partials, data);
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "</p>";
+ return buffer;
+ });
10 test/handlebars_test.js
@@ -140,5 +140,15 @@ exports.handlebars = {
test.equal(actual, expected, 'should support custom file name identifiers for partials.');
+ },
+ partials_use_namespace: function(test) {
+ 'use strict';
+ test.expect(1);
+ var actual ='tmp/partials_use_namespace.js');
+ var expected ='test/expected/partials_use_namespace.js');
+ test.equal(actual, expected, 'should allow partials to be added to template namespace.');
+ test.done();
Something went wrong with that request. Please try again.