Global variables in Handlebars if blocks - handlebars.js

Is it possibly to use global variables in Handlebars conditionals? I'm writing an app that lists a lot of objects, and I want users to be able to control which details are listed. For example, displaying only first names in a list of people, like so:
<ul>
{{#each people}}
<li>
<p>{{firstName}}</p>
{{#if displayLastnames}}
<p>{{lastName}}</p>
{{/if}}
</li>
{{/each}}
</ul>
I don't want to actually modify the data (for example, by removing the lastName attribute and doing {{#if lastName}}).

You can also register a global helper named 'displayLastnames' and use it in a if :
Handlebars.registerHelper('displayLastnames', function(block) {
return displayLastnames; //just return global variable value
});
and just use it as in your sample :
{{#if displayLastnames}}
<p>{{lastName}}</p>
{{/if}}

Handlebars namespaces the variables so you can't directly access global variables. Probably the easiest thing to do is to add your own helper, something simple like this:
Handlebars.registerHelper('if_displayLastnames', function(block) {
if(displayLastnames)
return block.fn(this);
else
return block.inverse(this);
});
and then in your template:
{{#if_displayLastnames}}
<p>{{lastName}}</p>
{{/if_displayLastnames}}
You'd probably want to put your "global" variables in their own namespace of course.
Demo: http://jsfiddle.net/ambiguous/Y34b4/

Related

Accessing an element within a list of Json objects using handlebars.js

"guests": [
{
"guestname": "john smith",
"is_active": false,
"guestheight": "175cm",
"guestprofile": "https://www.example.com"
},
{
"guestname": "david smart",
"is_active": false,
"guestheight": "175cm"
}
]
I would like to check if guestprofile exist. Given that I currently have a variable holding the index of the list we are trying to access here, namely itemIndex. So basically I'm trying to query if guests[itemIndex]["guestprofile"] in handlebars.js context.
If I make a direct reference like
{{#if guests.0.guestprofile}}
//do something
{{/if}}
its working fine. However, if I replace 0 with itemIndex like below, everything broke...
{{#if guests.itemIndex.guestprofile}}
//do something
{{/if}}
Currently I have also tried
{{#if (lookup guests itemIndex).guestprofile}}
//do something
{{/if}}
{{#if guests[itemIndex].guestprofile }}
//do something
{{/if}}
None of them actually worked. Please help, Thank you in advance!
You were so close with your lookup attempt.
The issue is that Handlebars does not allow you to chain a key onto a lookup subexpression as you are doing with (lookup guests itemIndex).guestprofile. It just doesn't resolve dynamic variables that way, which is the same reason why lookup has to be used instead of guests.itemIndex.guestprofile.
The part you missed is that you actually need two lookups - one to get the element of guests at itemIndex and the second to get the guestprofile of that element.
Your template needs to become:
{{#if (lookup (lookup guests itemIndex) 'guestprofile')}}
do something
{{/if}}
I have created a fiddle for your reference.

how to know 'each' done or re done in meteor blaze template

each running after onRendered and Tracker.autorun(if foo is binding subscription data context).
so i cant catch thateach` work is when done.
how to know each is work done, or rework and done?
is it unknown?
Below is an example.
<template name="something">
{{#each foo}}
<bar>bar</bar>
{{/each}}
</template>
I don't see a real use case for this but you can use a helper here that does not add anything to the render output:
<template name="something">
{{#each foo}}
<bar>bar</bar>
{{isDone #index foo}}
{{/each}}
</template>
Template.something.helpers({
isDone(index, arr) {
if (index === arr.length - 1) {
// this was the last element
// to be rendered. do whatever
// you want here
}
}
})
Not that this is not really a best practice and you should think about why you need to know this? If you have performance issues with your rendering you want review your whole template code design and refactor where necessary.

loop through an array of object with handlebars.js

I have a structure like this:
obj: {
array: [{
string: 'hello'
},
string: 'tim'
}]
}
how can i print all the string propery in an unordered list?
i'm trying with this but it doesn't print nothing
<ul>
{{#each array}}
<li>{{this string}}</li>
{{/each}}
</ul>
Try this code
<ul>
{{#each array}}
<li>{{this.string}}</li>
{{/each}}
</ul>
TL;DR: According to each helper code in the docs, context is set to current item.
Second argument implicitly passed to helper is options object, that contains fn property. This property is a function that behaves like a normal compiled Handlebars template (containing what have been placed between {{#each}} and {{/each}}).
Helper iterates over the array and evaluate the template for each item. Concatenated result is returned.
So, you don't have to use this.
<ul>
{{#each array}}
<li>{{string}}</li>
{{/each}}
</ul>
Fiddle Example

Passing through variable into partial and using an #is helper - Handlebars

I'm trying to pass a variable (tag name) into a Handlebars partial and use an #is block helper on the tag but for some reason it just won't play ball. This is my code:
Call to my partial and passing through the tag name.
{{> nav tagged='page' }}
In the partial itself I do the following (tagged is the variable name passed through):
{{#each tags}}
{{#is tag tagged}}
{{#each pages}}
// Do code here
{{/each}}
{{/is}}
{{/each}}
If I just render the tagged variable it displays the variable value as expected so a bit confused as to why its not working.
Thanks.
The issue you have is that the tagged variable is in the parent context but you're trying to reference it within the #each tags loop.
You can reference the parent context with ../ so the working code would be
{{#each tags}}
{{#is tag ../tagged}}
{{#each pages}}
// Do code here
{{/each}}
{{/is}}
{{/each}}

Meteor #each #index passed to Dynamic Template?

I'm trying to pass down the index of an item from an {{#each}} loop into a dynamic template, but am lost on how to get it there (in a clean way).
Current code:
{{#each item}}
{{Template.dynamic template=type data=this}}
{{/each}}
With this, {{#index}} is not accessible in the dynamically loaded template.
I also tried using a template helper, but it doesn't appear the index is tracked in the context.
{{#each item}}
{{Template.dynamic template=type data=itemData}}
{{/each}}
Template.items.helpers({
itemData() {
// can't access index in here
return this;
}
});
Can anyone advise on how I can achieve this?
Thanks!
Solved this using the following pattern:
... Template.Items
{{#each items}}
{{>Template.dynamic itemConfig #index}}
{{/each}}
Template.items.helpers({
itemConfig(index) {
const data = this;
data.index = index;
return {
data,
template: this.type //this.type is where im storing my template name
};
},
});
Using the #index as a helper param, and then Blaze uses the object as a config for the dynamic template!
:)
EDIT: I found another solution. Does the same job, and I prefer how it looks.
{{>Template.dynamic template=type data=(templateData #index)}}
Where templateData is essentially the same helper from before but just returns data with an index prop.
{{#each item}}
{{Template.dynamic template=type index=#index}}
{{/each}}
You can use 'index' in dynamic template to access index

Resources