Geraint Anderson
Geraint Anderson

Reputation: 3383

Access parent property in handlebars each where each is nested property

I am using handlebars to iterate over a nested array and display the data using a handlebars template, but I need to access a property that is not part of the array that I am iterating over. When the array is not nested, this works as expected. Here is an example (you can paste these directly into tryhandlebars):

Template:

<div class="entry">
  <div class="body">
    {{#each items}}
      <p>{{name}} - {{quantity}} {{../currency}}</p>
    {{/each}}
  </div>
</div>

Data:

{
  currency: 'GBP',
  items: [
    {
      name: 'apples',
      quantity: 5
    }, {
      name: 'bananas',
      quantity: 7
    }
  ]
}

But now I have a requirement to pass a whole new data structure to the template, so I am wrapping the fruit data as a property of another object:

{fruit: {
  currency: 'GBP',
  items: [
    {
      name: 'apples',
      quantity: 5
    }, {
      name: 'bananas',
      quantity: 7
    }
  ]
}}

I change the #each to iterate over fruit.items instead of items:

{{#each fruit.items}}
  <p>{{name}} - {{quantity}} {{../currency}}</p>
{{/each}}

Now, the name and the quantity are outputted correctly as before but the currency is blank. It seems the relative reference using ../currency no longer works. The only difference is the dot notation in the value passed to the each. How can I use the relative path in a nested property?

I have tried creating a helper function that takes the relative reference so I can inspect the values and can see the currency reference is undefined.

Upvotes: 1

Views: 1449

Answers (1)

76484
76484

Reputation: 8993

There is a little confusion here as to what the parent context is when within the #each.

As a tip, a good way to discover the parent context is to use Handlebars' built-in log helper.

Within our #each we can add {{log ..}} and Handlebars will print to the console the value of our parent.

In this case we get:

{
  fruit: {
    currency: 'GBP',
    items: Array(2) [...]
  }
}

This tells us that our parent is the root context and not the fruit object. This makes sense because we never "step-into" the context of fruit - for example, by using {{#with fruit}}{{#each items}} - but instead iterate fruit.items directly from the root.

This means we need only change our ../currency to ../fruit.currency. An alternative would be to use Handlebars' @root data variable to jump to our root context directly: @root/fruit.currency.

A second alternative is to use the #with helper as mentioned above. This creates a fruit context, allowing us to leave the #each part of the template as you had it in your post:

{{#with fruit}}
  {{#each items}}
     <p>{{name}} - {{quantity}} {{../currency}}</p>
  {{/each}}
{{/with}}

I have created a fiddle for your reference.

Upvotes: 4

Related Questions