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

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.

Related

How to render partials/helpers *inside* a string variable?

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.

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.

Can you pass a dynamic variable into a Meteor blaze template?

I saw the response to this stackoverflow post: Is there a way to pass variables into templates in Meteor?
The post only shows how to pass in a static value into blaze template. See the following example - I'm trying to pass in user.username into the template cookieTemplate
<template name="userTemplate">
<p> Wellcome {{user.username}} </p>
{{#each user.profile.cookies}}
{{> cookieTemplate username={{user.username}} }}
{{/each}}
</template>
<template name="cookieTemplate">
{{username}} has cookie {{this.cookieName}}
</template>
I know that I could potentially do this with Session.set('username', blah), but I was wondering if I can pass a dynamic variable into template?
A simple solution to yours is just to pass the user object to the template
{{> cookieTemplate user=user }}
and use it inside the template as
{{user.username}}
or you write down some helper to create a data object with relevant attributes like:
Template.userTemplate.helpers({
get_user: function() {
return { username: Template.instance().user.username }
}
and then call the template with
{{> cookieTemplate user=get_user }}
and use the value by
{{user.username}}
I made something similar (helper function) as a MeteorPad to this thread
Access an object's property names in a Blaze template
Maybe it helps you
Cheers,
Tom
Yes you can and might already be doing so.
In general if you are getting your data through auto publish or pub-sub, the data is considered reactive. Every time there is an update on the collection in anyway this update will be pushed to the template.
For your case, if you got the data through currentUser or Meteor.user() it would be the same case.

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

Meteor templates #if block does not evaluate multiple optiopns

I have an if statement which is checking for multiple roles as follows:
{{#if isInRole 'User' 'Admin'}}
{{> dashboard}}
{{/if}}
This conditional if block only checks for the first option, and does not evaluate the second one. For example, when a User logs in the dashboard template is rendered correctly, but when an admin logs in it is not rendered. Is there a specific way to specify this OR condition?
Actually this could be done like this when there are multiple options:
{{#if isInRole 'User, Admin'}}
{{> dashboard}}
{{/if}}
This should work fine if you just name the arguments:
{{#if isInRole arg1='User' arg2='Admin'}}
{{> dashboard}}
{{/if}}
You might have to amend your helper function to something that can handle arguments being passed in like that. This would work:
...
isInRole: function(args) {
return _.some(args.hash);
},
...
Note that the actual argument names are irrelevant, they just need to be supplied.

Resources