Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Nested Helpers #222

Closed
carlyle opened this issue Apr 20, 2012 · 17 comments
Closed

Support for Nested Helpers #222

carlyle opened this issue Apr 20, 2012 · 17 comments
Labels

Comments

@carlyle
Copy link

carlyle commented Apr 20, 2012

There are a good number of situations (at least in my experience) where it would be handy to be able to nest helper calls, such as capitalizing and pluralizing a word. Unless I've missed it, Handlebars doesn't seem to support doing so.

I could see the syntax being something like:

<h1>{{count}} {{capitalize {{pluralize type count}} }} Found</h1>
<span>Just click on the {{type}} you are looking for...</span>

or:

<h1>{{count}} {{capitalize pluralize(type count)}} Found</h1>
<span>Just click on the {{type}} you are looking for...</span>

Which, with count = 5, type = 'person', and a smart enough pluralize helper, would yield:

<h1>5 People Found<h1>
<span>Just click on the person you are looking for...</span>
@KevinGrandon
Copy link

Something like this, (or modifiers) would be nice. For now it's possible to do something like: {{capitalizePlural type count}}

You can create your own helpers and call them with something like:

Handlebars.registerHelper('capitalizePlural', function(type, count) {
    type = type.charAt(0).toUpperCase() + type.slice(1)
    return Handlebars.helpers.pluralize.call(this, type, count)
});

@carlyle
Copy link
Author

carlyle commented Apr 21, 2012

Of course, but that isn't particularly scalable.

@wagenet
Copy link
Collaborator

wagenet commented May 4, 2012

I think this is unlikely to be supported, but I'll leave this open for now.

@chrislondon
Copy link

I plus one this

@my8bird
Copy link

my8bird commented Aug 15, 2012

Here is a hack that works to all cascading helper calls. Basically, testing to see if the first argument is a function and if so calling it with the rest of the arguments to generate the result that this help wants to work on.

// Setup the helpers
Handlebars.registerHelper('sum', function(left, right) {
   return left + right;
});

Handlebars.registerHelper('numFormat', function(num) {
   // Hack around Handlebars by testing for function and using
   // that to calculate the num.
   if (typeof(num) == 'function') {
      num = num.apply(null, Array.prototype.slice.call(arguments, 1));
   }
   // Do that actual work
   return d3.round(num, 1);
});

// Use this template
var t = Handlebars.compile("{{ numFormat sum 1 2}} === {{ numFormat 3 }}");
assert('3 === 3', t());

@sandinmyjoints
Copy link

+1

@wycats
Copy link
Collaborator

wycats commented Oct 24, 2012

This is largely intentionally. For format tweaks, you can always define computed properties on your view to modify the format. One of the primary goals of Handlebars is to make the primitive syntax simple enough to make it possible for us to attach bindings without a lot of accidental mayhem.

If you look in the issue tracker, you'll see that there are still some issues related to interactions between existing helper styles (like if and bindAttr), and every new piece of possible syntax dramatically increases the interaction surface area.

Perhaps some day, when the existing bindings are extremely solid and mature, we can look into adding new features. For now, if it is possible to implement something via computed properties (or other existing primitives), I'm going to lean heavily in favor of using those primitives over adding new syntax.

@ghost
Copy link

ghost commented Jan 25, 2013

It could be great to have, something like applying i18n to existing views, else we need to extend views and do a lot of work around.
{{view "Bootstrap.Forms.TextField" valueBinding="account.name" label={{t frontend.signup.name}} }}

If someone has nailed this problem, kindly share with me.

@NkS90
Copy link

NkS90 commented Jan 29, 2013

@Trigmatic: +1

@ashugit
Copy link

ashugit commented Jan 29, 2013

@matt001 I had tried using the thing indirectly
Handlebars.registerHelper "T", (key, options) ->
ret = options.fn( i18Label: I18n.t(key) )

{{#T frontend.signin.password}}
{{view "Bootstrap.Forms.TextField" valueBinding="view.account.password" label=i18Label type="password"}}
{{/T}}

But looks so dirty, a nested helper for this very case made sense.

@mateusmaso
Copy link

@Trigmatic +1

the same problem happened to me #432 and the only solution I found was compiling those nested helpers at runtime, but it seems wrong because if you nest too deep it gets ugly. Most of the problems that led me to this was likely internationalization helpers and custom classes with "if" statements.. I saw that Ember.js solve this last problem with string statements which makes smells even more.

@mateusmaso
Copy link

by the way, just created a handlebars plugin for it as a workaround for now https://github.com/mateusmaso/handlebars.nested

@machineghost
Copy link

+1

1 similar comment
@yagudaev
Copy link

+1

@james-andrewsmith
Copy link

I know this isn't exactly in line with the spec/best practices, but if anyone is trying to make the hack @my8bird posted work with the the newer versions of handlebars the following snippet will modify the compiler to generate compatible functions.

Handlebars.JavaScriptCompiler.prototype.lookupOnContext = function(name) {
    this.push(this.nameLookup('depth' + this.lastContext, name, 'context') + ' || helpers.' + name);
};

@justinperkins
Copy link

i18n begs for this addition

@leonardorb
Copy link

+1

@ghost
Copy link

ghost commented Jan 31, 2014

Great news for all that need this.
Support has been added in version 1.3.

From the docs: http://handlebarsjs.com/expressions.html

Subexpressions

Handlebars offers support for subexpressions, which allows you to invoke multiple helpers within a single mustache, and pass in the results of inner helper invocations as arguments to outer helpers. Subexpressions are delimited by parentheses.
{{outer-helper (inner-helper 'abc') 'def'}}
In this case, inner-helper will get invoked with the string argument 'abc', and whatever the inner-helper function returns will get passed in as the first argument to outer-helper (and 'def' will get passed passed in as the second argument to outer-helper.

So you can now do something like:

{{ myHelper text=(i18n "text") }}

Thanks for adding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests