i want fine control of whitespace but still have readable templates.
Just wanted to see if other's solution to by simple use case.
{{name}}
{{#if age}}
, {{age}}
{{/if}}
# outputs {{name}} , {{age}}
# desire: {{name}}, {{age}}
https://github.com/wycats/handlebars.js/issues/479 - submitted a ticket which was closed.
Following the history from the pull request to add this feature it looks like this is the correct syntax:
<h4>
{{~#object~}}
Surrounding whitespace would be removed.
{{/object}}
</h4>
Result:
<h4>Surrounding whitespace would be removed.</h4>
There is also this syntax which trims only leading whitespace:
<h4>
{{~#object}}
Only leading whitespace would be removed.
{{/object}}
</h4>
Result:
<h4>Only leading whitespace would be removed.
</h4>
Just a comment to Brian answer, If you want to trim whitespace AND do not want handlebars to escape your expression at the same time, the correct syntax to be used is:
{{~{EXPRESSION}~}}
(trimming whitespace before and after the expression while not escaping it)
The Handlebar's Whitespace Control Documentation can be found here:
https://handlebarsjs.com/guide/expressions.html#whitespace-control
Template whitespace may be omitted from either side of any mustache statement by adding a ~ character by the braces. When applied all whitespace on that side will be removed up to the first handlebars expression or non-whitespace character on that side.
These two, comma-list examples would have the same output:
Case 1:
{{#each listItems as |item index|}}
{{#if (eq index 0)}}
{{~item.name~}}
{{else~}}
, {{item.name~}}
{{/if}}
{{/each}}
Case 2:
{{#each listItems as |item index|}}
{{#if (eq index 0)~}}
{{item.name}}
{{~else~}}
, {{item.name}}
{{~/if}}
{{/each}}
I think the cleanest implementation of this would be to add {{"\n"~}} where you want a hard-stop on new lines.
The "\n" can technically be anything except for empty, ie "". I used "\n" to make it clear what I am doing in the editor.
Example
Three empty lines after this
{{"\n"~}}
Three empty lines before this
Two empty lines before this. No empty lines after this.
{{~"\n"~}}
No empty lines before this.
Result
Three empty lines after this
Three empty lines before this
Two empty lines before this. No empty lines after this.No empty lines before this.
Basically, as others have said, any helper can be prefixed or suffixed with ~. Here, I've decided to pass a value that won't render as the helper ("\n") which allows us to pass ~ freely to control before and after whitespace.
Edit
Alternatively:
Handlebars.registerHelper(
'singleLineOnly',
function (options) { // "this" cannot be provided to inline function!
return options.fn(this).replace(/[\r\n]+/gm, '')
}
)
Handlebars.registerHelper(
'singleSpaceOnly',
function (options) { // "this" cannot be provided to inline function!
return options.fn(this).replace(/\s\s+/g, ' ')
}
)
Which will allow you to take something like this:
{{#each this}}
{{#singleLineOnly}}
{{#singleSpaceOnly}}
{{calculatedAmount}}
{{!an example comment}}
{{#if unitOfMeasure.translate}}
{{{unitOfMeasure.translate.value}}}
{{/if}}
{{!some random comment}}
{{#unless unitOfMeasure.translate}}
{{{unitOfMeasure.value}}}
{{/unless}}
{{!Some random comment}}
{{#ifNotEquals (lowerCase product.value) "other"}}
{{!If translated, use translated UOM}}
{{#if product.translate}}
{{{product.translate.value}}}
{{/if}}
{{!If not translated, use default UOM}}
{{#unless product.translate}}
{{{product.value}}}
{{/unless}}
{{/ifNotEquals}}
{{!just some more logic for example}}
{{#ifNotEquals (lowerCase ingredient.value) "other"}}
{{!If translated, use translated UOM}}
{{#if ingredient.translate}}
{{{ingredient.translate.value}}}
{{/if}}
{{!If not translated, use default UOM}}
{{#unless ingredient.translate}}
{{{ingredient.value}}}
{{/unless}}
{{/ifNotEquals}}
<br/>
{{/singleSpaceOnly}}
{{/singleLineOnly}}
{{/each}}
And end up with this:
1/2 oz. first ingredient <br/>
1 pump(s) another ingredient <br/>
3/4 oz. this ingredient <br/>
2 shot(s) that ingredient <br/>
last instruction <br/>
{{#singleLineOnly}} and {{#singleSpaceOnly}} can be used as a wrapper for any text. You'll most likely want to use these with ~ for additional before/after whitespace control. For example: {{~#singleLineOnly~}}
You can add a Handlebars Helper to trim() whitespace
{{#-}}
Surrounding whitespace would be removed.
{{/-}}
more background info: https://github.com/wycats/handlebars.js/pull/336
Related
I trying to assign a dynamic value title to a new variable carat1 with a custom helper, but it currently isn't working.
{{#each items}}
{{assignVar "jsondata" '{["title": "{{title}}", "id": `{{id}}`, "param_name": "{{param_name}}"]}'}}
{{getVar "jsondata"}}
{{assignVar "carat1" "{{title}}" }}
{{getVar "carat1"}}
{{/each}}
When I evaluate the code above, I see the literal string "{{title}}" printed but actual title value is "this is my title".
You want to use a subexpression here.
That is, in your assignVar helper, you don't want to pass the literal string "{{title}}" as the 2nd argument, but want the value of title.
Subexpressions are delimited by parentheses.
So instead of "{{title}}", you'd just write (title) to evaluate the title variable within the assignVar helper.
{{#each items}}
{{assignVar "jsondata" '{["title": "{{title}}", "id": `{{id}}`, "param_name": "{{param_name}}"]}'}}
{{getVar "jsondata"}}
{{assignVar "carat1" (title) }}
{{getVar "carat1"}}
{{/each}}
How can I write an if not x statement in an HBS template file?
At present, I use an if/else clause in order to achieve that:
{{#if x}}
{{else}}
Some Text
{{/if}}
Is there a way to simplify this and use a single if statement?
I've tried stuff like {{#if !x}} and {{#if ^x}}, but it didn't work of course.
Looking on the web for HBS logical operators, I couldn't quite find the syntax for a logical-not.
Update
I should emphasize that in my case x is undefined.
I've learned it "the hard way", while trying:
{{#if not x}}
Some Text
{{/if}}
Which threw TypeError: Cannot read property 'includeZero' of undefined.
Have you tried unless?
<div class="entry">
{{#unless license}}
<h3 class="warning">WARNING: This entry does not have a license!</h3>
{{/unless}}
</div>
You can use the unless helper as the inverse of the if helper. Its
block will be rendered if the expression returns a falsy value.
https://handlebarsjs.com/builtin_helpers.html
You can also considers custom helpers:
Handlebars.registerHelper("ifNot", function(a, options){
if (!a) {
return options.fn(this);
}else{
try{
return options.inverse(this);
}catch(e){
//no else statement
}
}
});
I have the following code:
{{#if true}} An {{else}} A {{/if}
That's the entire template. It's loading fine. But notice the #if condition is simply true. If I put anything other than a literal there, it doesn't work. Any variable I put, any sort of programmatic expression like {{#if 3 > 5}}, it gives me a Parser Error:
Error: Parse error on line 36:
{{#if 3 > 5 }} An {{else}} A
---------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'
I can't figure that out. I even reduced it to just {{#if 3 > 5}} A {{/if}} and it still gives a parser error.
So I thought maybe you have to use a helper for this sort of thing, but I can't get any helper I register to work either.
Turns out the #if helper can only test for properties to be true or false – not arbitrary expressions[source], so you have to do everything with helpers. Just write a function to compare things with logical operators and return true or false.
And to save you some trouble, the syntax for calling helpers doesn't use parentheses, either....arguments are space-separated like in rails. So it looks like:
{{myHelperFunction myarg1 myarg2}}
And if you want to nest helpers, you need parens:
{{myOuterHelper (myInnerHelper myarg1 myarg2)}}
Last tip from me, if you want to nest your helper with an #if, you need parens, too:
{{#if (myHelper myarg1 myarg2)}} content {{/if}}
Is it possible to render a template, or even just a partial, from within the context passed to a top level template? It seems like this might require recursive rendering, but maybe I'm missing something.
The example below demonstrates this using Bootstrap.
Say this is my top level template:
<div class="panel">
<div class="panel-body">
{{{description}}}
</div>
</div>
And my context is:
{
description: "\
Some text before the warning.\
<div class=\"alert alert-warning\" role=\"alert\">\
<span class=\"glyphicon glyphicon-warning-sign\" aria-hidden=\"true\"> </span>\
My warning here.\
</div>\
Some text after the warning."
}
What I'd like to do is separate the alert into a partial for a number of reasons:
Arbitrary placement within surrounding text
Can make partials for types other than warning (danger, info, etc.)
Can add as many as needed interspersed in the context string
For these reasons, it seems like it's not possible to put it into the top level template.
The partial would look something like this:
<script id="partial-warning-template" type="text/x-handlebars-template">
<div class="alert alert-warning" role="alert">
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"> </span>
{{{warning-message}}}
</div>
</script>
Once this is in place, I would be able to use it like so:
{
description: "\
Some text before the warning.\
{{> partial-warning-template \"My warning here.\"}}\
Some text after the warning.\
{{> partial-warning-template \"Now adding a second warning.\"}}"
}
Maybe I'm missing something fundamental - is there a more idiomatic way of doing this?
You won't be able to include the partial blocks in the description value and expect them to be evaluated as partials by the top level template method; the entire description string will be spat out as a single literal string.
What you would need to do is to have the partials evaluated before you pass the context object with description to the top level template method.
If you have pre-compiled your partial in something like the following manner:
Handlebars.registerPartial('warn', Handlebars.compile(document.getElementById('partial-warning-template').innerHTML));
Then you will be able to call this partial when you construct your description string:
{
description: 'Some text before the warning.' +
Handlebars.partials.warn({ 'warning-message': 'My warning here.' }) +
'Some text after the warning.' +
Handlebars.partials.warn({ 'warning-message': 'Now adding a second warning.' })
}
I'm having an issue with a Session variable that I am using to keep track of a search query when using alongside the Meteor Typeahead package.
When I log the variable in the console the last character displays but when I output my helper in the template that Typeahead calls, it omits the last character.
My event:
Template.bookSearchForm.events
'keyup .typeahead': (e) ->
bookVal = e.target.value
Session.set 'bookSearchValue', bookVal
My helper:
Template.searchNoItems.helpers
bookSearchValue: ->
return Session.get 'bookSearchValue'
My template:
<template name="searchNoItems">
<div class="search-no-results">
<span class="lookupBook">Search for {{ bookSearchValue }}</span>
</div> <!-- /.search-no-results -->
</template>
Any ideas would be greatly appreciated. Just to confirm, the console is spitting out the full query eg: "My Query" whereas in the helper it's only outputting: "My Quer".
Thanks for taking a look.
use this {{{ bookSearchValue }}} notice it's 3 curly braces
Handlebars/Spacebars HTML-escapes values returned by a
{{expression}}. If you don't want to escape a value, use the
"triple-stash", {{{