215

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!

Drew Noakes
  • 266,361
  • 143
  • 616
  • 705

3 Answers3

447

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.

cincodenada
  • 2,492
  • 17
  • 35
Drew Noakes
  • 266,361
  • 143
  • 616
  • 705
  • 102
    Just a note on using ../ to get parent properties. If you have a each statement with a nested #if then just doing ../ only gets you to the level of the #each. So you have to do ../../itemSize to get back to the parent outside of the #each – TheStoneFox Mar 26 '13 at 16:43
  • 1
    How can I get this functionality in mustache.js templating engine ? – Simon Polak Nov 01 '13 at 09:37
  • 2
    @blushrt you don't. That's handlebars specific – 19h Feb 15 '14 at 15:42
  • 3
    @TheTaxPayer you just saved me an immense amount of headache! rock on with your socks on :) – Peter P. Mar 19 '14 at 02:57
  • 4
    What about passing an upper level #each value into a helper – Oleg Belousov Feb 03 '15 at 10:12
  • Does this work with all versions of handlebars ? I am trying the same with handlebars.runtime-v1.1.2 and it doesn't work.. !! – Yugandhar Pathi May 13 '15 at 13:17
  • @YugandharPathi, looks like 1.1.2 was released in Nov 2013 which is after this answer was posted, so yes it should work. Maybe open a new question that explains your problem. – Drew Noakes May 13 '15 at 14:02
  • To expand a little, this works with other block helpers like #with. Props to @Theston.EFox for his comment as well. – Javier Constanzo Jun 15 '15 at 14:48
  • This is completely unreadable with large blocks but also appears to be the only solution – sricks Jan 05 '16 at 23:33
  • Please see @caballerog's answer below - `@root` ftw! https://stackoverflow.com/a/36725440/422845 – jbyrd Oct 24 '18 at 14:42
  • A note that @TheStoneFox's comment no longer applies as of Handlebars 4 - #if no longer introduces an extra level. – cincodenada May 21 '20 at 02:56
65

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.

caballerog
  • 2,521
  • 1
  • 16
  • 32
  • 1
    Going up one level for me worked using "@root.itemSize". – Sam Tyson Jul 27 '16 at 17:23
  • Technically that's not going up one level - it's going down one level from root, and works only if you are one level down. This approach does not work if you do not know your current nesting level. – Etherman Oct 16 '20 at 08:13
0

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?

Etherman
  • 1,447
  • 1
  • 19
  • 31