Search code examples
javascripthtmltemplateshandlebars.jskeystonejs

Handlebars Scope Issue: Can't access template variable from embedded `each`


I am trying to figure out why I can't access my template variables from within an embedded each statement in my handlebars template (rendered within my keystone project). I have read numerous issues here on StackOverflow with similar problems, but none of them solved my particular use case.

I have a simple data object that gets passed to the Handlebars template that looks [roughly] like this:

{ 
   rootPath: '../../../', 
   navigation: { all: { 'a': { sublinks: [Object] }
}

My question is:

Why does the rootPath template variable print perfectly in {{#each navigation.all}}, but inaccessible from within {{#each sublinks}}?

Here is my Handlebars template:

<!-- rootPath prints fine here -->
Here is your rootPath variable: {{rootPath}}

{{#each navigation.all}}

    <!-- rootPath prints fine here -->
    top-level rootPath: {{../rootPath}}

    {{#if sublinks}}

            {{#each sublinks}}

                <!-- WHY WON'T ROOTPATH PRINT HERE?? -->
                <!-- Obviously, I am trying the three possible scope paths -->
                sub-level rootPath attempt 1: {{../../rootPath}}
                sub-level rootPath attempt 2: {{../rootPath}}
                sub-level rootPath attempt 3: {{rootPath}}

            {{/each}}

    {{/if}}

{{/each}}

I get the following output (notice how all the sub-level attempts don't have access to the rootPath template variable):

Here is your rootPath variable: ../../../
top-level rootPath: ../../../
sub-level rootPath attempt 1:
sub-level rootPath attempt 2:
sub-level rootPath attempt 3:

What I need is for the rootPath to be available everywhere, so I can get something like this:

Here is your rootPath variable: ../../../
top-level rootPath: ../../../
sub-level rootPath: ../../../

So what scoping issue or syntax am I missing here?

I am using Handlebars version 2.0.0, as that is what comes pre-packaged by keystone.


Solution

  • I was able to solve the issue by using the @root token.

    Simply calling @root.rootPath from within the embedded {{#each sublinks}} was enough to solve my problem.

    Here is the correct template markup:

    Here is your rootPath variable: {{rootPath}}
    
    {{#each navigation.all}}
    
        top-level rootPath 1: {{../rootPath}}      <!-- works -->
        top-level rootPath 2: {{@root.rootPath}}   <!-- works -->
    
        {{#if sublinks}}
    
                {{#each sublinks}}
                    sub-level rootPath 1: {{@root.rootPath}}  <!-- works -->
                    sub-level rootPath 2: {{../../rootPath}}  <!-- doesn't work -->
                {{/each}}
    
        {{/if}}
    
    {{/each}} 
    

    Which yields the following output:

    Here is your rootPath variable: ../../../
    top-level rootPath 1: ../../../
    top-level rootPath 2: ../../../
    sub-level rootPath 1: ../../../
    sub-level rootPath 2: 
    

    Note: for the top-level rootPath (in {{#each navigation.all}}, I could use either one of these:

    {{../rootPath}}      <!-- works -->
    {{@root.rootPath}}   <!-- works -->
    

    However, from within the embedded {{#each sublinks}}, only the @root.rootPath seemed to work:

    {{@root.rootPath}}  <!-- works -->
    {{../../rootPath}}  <!-- doesn't work -->