Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

Closed
wants to merge 1 commit into from

4 participants

Phil Dokas Tyler Kellen Thanasis Polychronakis Pete Hawkins
Phil Dokas

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.

Tyler Kellen
Owner

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?

Thanasis Polychronakis

@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.

Pete Hawkins

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.

Phil Dokas

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 http://foo.com/posts/123/ to http://foo.com/posts/123/meta/. 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.

Thanasis Polychronakis

@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.

Phil Dokas

@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.

Thanasis Polychronakis

@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.

Phil Dokas

@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}}
Thanasis Polychronakis

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 ?

Phil Dokas

@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
Thanasis Polychronakis

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

Phil Dokas

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

Tyler Kellen
Owner

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

Phil Dokas

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

Tyler Kellen
Owner

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

Phil Dokas

All set!

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

Closes gh-33.
f7b1733
Tyler Kellen tkellen closed this in f7b1733
Phil Dokas pdokas deleted the 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. Phil Dokas

    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
View
@@ -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/handlebars-options.md
View
@@ -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
View
@@ -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
View
@@ -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 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.name; 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
View
@@ -140,5 +140,15 @@ exports.handlebars = {
test.equal(actual, expected, 'should support custom file name identifiers for partials.');
test.done();
+ },
+ partials_use_namespace: function(test) {
+ 'use strict';
+ test.expect(1);
+
+ var actual = grunt.file.read('tmp/partials_use_namespace.js');
+ var expected = grunt.file.read('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.