How to render partials/helpers *inside* a string variable? - handlebars.js

Say I've got the following template/scenario:
{{partial-container container}}
{{{content.html}}}
{{#each content.partials}}
{{this}} // <-- here I'd like to render partials that users requested.
{{/each}}
Goals
[Done] I want to render a block of text, html-escaped, using the html property.
From the JSON, we also get a list of "partials" to render, but I can't figure out how to make this work.
Ideally, the syntax would be something like this:
{{partial-container container}}
{{{content.html}}}
{{#each content.partials}}
{{ > {{this}} }}
{{/each}}
But that throws a syntax error. Is there any way to interpret the contents of a variable as the name for a partial to render (and do so)?

I am assuming that your "list of partials" is an array of names matching with registered partials. Something like:
"partials": ["fooPartial", "barPartial", "fooPartial"]
The Handlebars documentation states that partials can be dynamically selected using a subexpression, but this subexpression must be a function that returns the partial name. This means that something as simple as {{> (this)}} will not work because our this is the string value of our partial name and not a function.
I see two ways of achieving our goal.
Option 1: Map the partial names to functions
If we have the ability to modify the data we are sending to our template, we could map the partial names into functions that return the name:
"partials": ["fooPartial", "barPartial", "fooPartial"].map(partialName => () => partialName)
These functions would allow us to dynamically insert our partials into our template with {{> (this)}}.
See this fiddle for an example.
Option 2: Use the lookup helper
If modifying our input data is not an option, we can use the Handlebars built-in lookup helper. The trick here is that, within our #each loop, we must step-up a context-level to get our partials array and then use the #index helper variable to get the partial name at the current index. The template would become:
{{#each content.partials}}
{{> (lookup ../content.partials #index)}}
{{/each}}
See this fiddle for an example.

Related

In HBS how do I display other variable's data inside foreach [duplicate]

Consider the following simplified data:
var viewData = {
itemSize: 20,
items: [
'Zimbabwe', 'dog', 'falafel'
]
};
And a Handlebars template:
{{#each items}}
<div style="font-size:{{itemSize}}px">{{this}}</div>
{{/each}}
This won't work because within the each loop, the parent scope is not accessible -- at least not in any way that I've tried. I'm hoping that there's a way of doing this though!
There are two valid ways to achieve this.
Dereference the parent scope with ../
By prepending ../ to the property name, you can reference the parent scope.
{{#each items}}
<div style="font-size:{{../itemSize}}px">{{this}}</div>
{{#if this.items.someKey}}
<div style="font-size:{{../../itemSize}}px">{{this}}</div>
{{/if}}
{{/each}}
You can go up multiple levels via repeating the ../. For example, to go up two levels use ../../key.
For more information, see the Handlebars documentation on paths.
Dereference the root scope with #root
By prepending #root to the property path, you can navigate downwards from the topmost scope (as shown in caballerog's answer).
For more information, see the Handlebars documentation on #data variables.
The new method is using dot notation, the slash notation is deprecated (http://handlebarsjs.com/expressions.html).
So, the actual method to access to the parents elements are the following:
#root.grandfather.father.element
#root.father.element
In your specific example, you would use:
{{#each items}}
<div style="font-size:{{#root.viewData.itemSize}}px">{{this}}</div>
{{/each}}
Another method from the official documentation(http://handlebarsjs.com/builtin_helpers.html) is using alias
The each helper also supports block parameters, allowing for named
references anywhere in the block.
{{#each array as |value key|}}
{{#each child as |childValue childKey|}}
{{key}} - {{childKey}}. {{childValue}}
{{/each}}
{{/each}}
Will create a key and value variable that children may access without
the need for depthed variable references. In the example above, {{key}} > is identical to {{#../key}} but in many cases is more readable.
Unfortunately ../ dereferencing does not seem to work through partials. But we can add properties to the context passed into the partial:
Name: {{parent.name}}
{{#each children}}
{{> childpartial this parent=../parent}}
{{/each}}
childpartial:
{{name}} is child of {{parent.name}}
More:
handlebars - is it possible to access parent context in a partial?
We can access parent using {{../parent.propertyname}}
Assume that you need to use if statement inside each block. Use built-in lookup property for reaching a root object whose key can be given dynamically by an outer each loop, for example.
The following works in both an each loop and nested each loop as well:
{{#each anArray}}
{{#each (lookup ../anObject this)}}
{{#if (lookup #root name)}}
`Something to be shown if the value of 'name' here can be found as a key at the root object and, if its value is boolean, its value is 'true'.`
{{/if}}
{{/each}}
{{/each}}
anArray is an array given at the root object.
anObject is an object given at the root object.
anObject has a name property.

How can I access the parameter of a Handlebars inline partial from inside a loop?

I'm working on a Handlebars project and trying to use an inline partial. I'm trying to access the key parameter from within a loop.
{{#*inline "myPartial"}}
<div class="actionOverlay">
{{#each (lookup items key) }}
<span class="{{classes}} key-{{key}}" title="{{title}}"></span>
{{/each}}
</div>
{{/inline}}
And then invoking this inline partial with {{> myPartial key="0R"}}. The variable items is an array of objects with classes and title as keys.
Unfortunately {{key}} renders as empty string, no doubt because there is no key key in the items objects. I've also tried {{#root.key}} and that doesn't work.
How can I access the partial's parameter from within the loop?
Please note that I'm not trying to use a partial from within a loop, but trying to use a loop in a partial and to access the partial's parameter from within the loop.

Want to pass a variable to a partial, that contains a helper name like if or ifequals

I would like to pass a partial a variable that contains a helper, so that the partial can better reused, However, my companies installed version of handlebars will not accept new helpers.
data eg:
{
"orderLines":[
{"unitPrice": "0.46","isItemUnavailable": "Y"},
{"unitPrice": "0.46"}]
}
Template 1:
{{> myPartial helpername="if" totest="isItemUnavailable"}}
Inside myPartial:
{{#each orderLines}}
{{#helpername totest}}
// stuff here if isItemUnavialable
{{/helper}}
{{/each}}
The problem as I see it, is that I cannot pass a variable to my partial in order to dynamically set a helper?
The outcome of the above is an error in the partial, saying it cannot find helper "helpername" even though it is supposed to render "if"
The partial passes the variable if. But when you place it beside a hash, it no longer accepts it as a variable with a value, but looks for #helpername as a registered helper, which then throws an error because there isn't one.

How can I use an expression with the context of the call location as a parameter in a partial?

For example in a handlebars template:
{{#each data }}
{{> partial parameter=somethingFromThisContext }}
{{/each}}
and then in my partial:
{{ somethingFromThisContext }}
{{ data }}
Neither of them work. If I use a string as a parameter instead of data, the string will display, but all the other expressions in the partial will no longer work.
I'm not sure if I've understood you correctly, but you seem to have misunderstood handlebars' partial behaviour.
Inside a partial your scope will not be accessible, so you won't have access to any parameters you have in the template where you call your partial.
To pass parameters you have to assign them in the partial call like you did:
{{> partial parameter=somethingFromThisContext }}. However you've renamed your somethingFromThisContext to parameter now. So it's accessible like so: {{parameter}}.
It's like doing something like this in any programming language:
paramter = somethingFromThisContext;
There is a pretty nice Documentation page here, which may guide you further.

In Spacebars, can you combine an inclusion argument with a data object?

This is something I've come across a few times. I'd like to do
{{> subtemplate item foo="bar"}}
So that the data context in subtemplate has all the item fields plus a foo field. Don't see any way to do this in the docs
https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md
I know I could make my own helper combine to use like this: {{> subtemplate combine item "foo" "bar"}}, but am hoping there's a better way.
Can you use dynamic template to pass in your data context?
{{> Template.dynamic template=template [data=data] }}
See http://docs.meteor.com/#/full/template_dynamic

Resources