2

I am confused by "scope" in the Handlebars template engine. In its documentation on block helpers, I read

"Private variables provided via the data option are available in all descendent scopes. Private variables defined in parent scopes may be accessed via pathed queries."

I understand the meaning of scope as used in programming languages (where {} are often used to create scopes). But what does "scope" refer to in Handlebars templating?

flow2k
  • 3,999
  • 40
  • 55

1 Answers1

4

It is actually quite similar, see an example here: https://jsfiddle.net/veraee/63gs19j3/11/

Just to make it clear, there are two types of "variables" in handlebars:

  1. The model/context. This is the data you inject into the template on redering. Use this for your normal work. These variables are referenced in the template via its name in {{}}:

    {{firstname}}

and are exposed in the javascript of the helpers via "this":

this.firstname
  1. The "@"-variables. This data is generated inside the helpers via javascript. These variables are referenced in the template via its name with '@'-prefix:

    {{@foo}}

and are exposed in the javascript of the helpers via "options.data":

options.data.foo

The citation from the handlebars doc in the OP is about number 2.

In a programming language the "{" enters a scope, in handlebars a block "{{#myBlock..." enters a scope.

Similar to the programming language you can use all variables from the outer scope in the inner scope (foo, bla), but if you redefine one in the inner scope (bla), the original value will be shadowed in the inner scope. When leaving the inner scope and being again in the outer scope, you get the old value of bla again.

But note these differences to programming languages:

  1. This scoping does not happen by some magic of the programming language syntax, you have to do in on your own, as the doc also mentions, i.e. this way:

    data = Handlebars.createFrame(options.data);

  2. As a bonus, you can reach the shadowed variables (which is usually not possible in programming languages) by prefixing the name with "../" which means: look at the previous (aka. outer) scope (see the "{{@../bla}}" in the inner scope in the example).

Oliver Erdmann
  • 361
  • 1
  • 5
  • Thanks for this detailed answer. The only thing that I am uncertain about is your second last point, where you seem to say one has to use `createFrame(.)` to create a new scope. Perhaps you didn't mean this, because earlier you said a new scope is created simply upon entering the block within a helper (which I agree with), like this, for instance: `{{#each myObject.myArray}} {{!-- myObject.myArray is now the (inner) scope--}} {{/each}}` – flow2k Nov 22 '17 at 19:15
  • 1
    You seem to confuse the two types of variables. To have a new scope for the @-variables (Number 2 in the first list) you have to enter a block (which in handlebars always involves a helper - myBlock in my example) _and_ in the helper's implementation you have to use createFrame. Fortunately, all buildin helpers in handlebars are implemented this way. – Oliver Erdmann Nov 22 '17 at 23:20
  • Your example is about context switch (Number 1 in the first list). This is something different. The implementation of a helper is free in what to put into the context for the body of the block: One helper simply puts the same context into it (as in my example) or, as the buildin "each" helper, one can put only a subset of the outer context into it, or even some completly self made context. The buildin "each" helper sets the context to the one current loop element and defines a @index variable (in the scope of the block), which contains the loop index. – Oliver Erdmann Nov 22 '17 at 23:20
  • 1
    Wow. Interesting. I think I was initially confused by the meaning of scope, because it seems to apply to context (Type 1 in your list), as well. For example, within the template, in a helper, you can use `..` to access the parent context: `{{#each childNode1.moreNodes}} Parent's room has {{../someAdultStuff}}. {{/each}}` – flow2k Nov 23 '17 at 00:49
  • You're right, in the section of the doc I linked to, this is not at all the meaning of scope - it is in reference to variable Type 2. I never made the connection between `@` variables and `options.data`. How did you discover this, if I may ask? Did you have to read the handlebars.js library source code? Or perhaps I skimmed the doc too quickly... – flow2k Nov 23 '17 at 00:49
  • Lastly, what's interesting is that the `@root` variable (Type 2) actually refers to the root context (Type 1) variable. – flow2k Nov 23 '17 at 00:51