Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

../ path only reaches up to the parent, not the root #245

Closed
EntitySpaces opened this Issue May 25, 2012 · 11 comments

Comments

Projects
None yet
5 participants

I'm using Handlebars.VERSION = "1.0.beta.6";

and my javascript looks like this

var data = {};
data.UI = {};
data.UI.isChecked = "true";
data.Database = database;
output = tmpl(data);

My template looks like this ...

isChecked :: {{../../UI.isChecked}}

Notice I have to use "../../" twice to climb back up to the root ( I'm deeply nested in an #each loop) I was under the understanding that a single "../" would take me up to my root object or "data" such that anywhere in my tempate I can do this

isChecked :: {{../UI.isChecked}}

no matter if i'm 14 levels nested in an {{#each}} loop, as it stands now, one has to know how many levels they are nested and use the appropriate number ../ to get back to the top, possibly 10 or more, this makes the Path feature unusable.

Here is a jsfiddle showing the issue, it's using 1.0.0.beta4.js and I have to use double "../../" ?
http://jsfiddle.net/GMrnz/42/

The help says this:

The ../ path segment references the parent template scope, not one level up in the context. This is because block helpers can invoke a block with any context, so the notion of "one level up" isn't particularly meaningful except as a reference to the parent template scope.

If that means we need to do things like isChecked = {{../../../../../../../../../../UI.isChecked}} when we are deeply nested can we please have this?

The Requested Fix/Enhancement

isChecked = {{~/UI.isChecked} where a tilde means "Start at the root"

Collaborator

wagenet commented May 25, 2012

@EntitySpaces You're correct that ../ only goes up one level, not to the root. I think you might want to consider a different set up for your templates, as this isn't something we're likely to support.

@wagenet wagenet closed this May 25, 2012

would it really be hard to implement {~/} as meaning the root of the context. This is kind of a big deal, imagine your doing code generation, there are lots of choices in the UI of that control what you want, ie, DataContract support, certain properties and methods, and now, everywhere you have to write these crazy ../../../../ things to get to the UI section which contains the users choices.

woudn't it be easy to parse {/UI.isChecked} and recognise that {/} means start at the root of the context passed into the template? I looked at the source and couldn't find where ../ is parsed or I would add it and issue a pull request.

It really seems like this would be a powerful feature, Knockout supports it with the $root property. I would think the context is a variable available the tempate during execution and {~/} would just mean "start there".

Collaborator

wagenet commented May 25, 2012

If you're interested, you can always send a pull request and we can evaluate from there.

Okay, I'll fork and add the feature, it's really a must have for a template engine

Collaborator

wagenet commented May 25, 2012

While I understand that it's important to you, I think it's hard to claim it's a must-have. Handlebars has fairly wide adoption without it.

I'm thinking I might be able to do this is with a Handlebars.registerHelper() method. By chance could I return the root context in a helper?

thus UI would be handled by a helper which merely returned the root object

phairow commented Jul 2, 2012

this would also be useful for referencing from within partials since the ../ notation does not work to reference scope outside of the partial.

Sure, it's not a "must have". However, I do know I (and many others) have spent much time debugging output trying to figure out why a particular object is missing... only to find out it got broken when quickly wrapped in an #each block. The need for a way to reference root in Handlebars is absolutely no different than the need to reference root on a file system. @wagenet: Could you explain specifically why not to do this? If anything, it makes templates cleaner, less prone to breaking, and makes references more straightforward.

Add this to your code (not to the handlebars.js file, just in your code somewhere)

Handlebars.JavaScriptCompiler.prototype.nameLookup = function (parent, name, type) {

    if (name.indexOf("xRoot") === 0) {
        return "data." + name;
    }

    if (/^[0-9]+$/.test(name)) {
        return parent + "[" + name + "]";
    } else if (Handlebars.JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
        return parent + "." + name;
    }
    else {
        return parent + "['" + name + "']";
    }
};

Then in your "data" add something like

data.xRoot.value = 1;

Then, anywhere in your code you can do this (even nested in an each) ...

{{#each Columns}}
{{xRoot.value}}
{{/each}}

I'm using this technique in my code everywhere, you can get to data in the root using xRoot as the prefix but it has to be that way in your data. I tried ~ but handlebars filters that as an error before I get a chance to trap it,

I also think this would be very useful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment