Hugo Scope Variable In Template

August 27, 2017
Use .Scratch to set outer scope variable or use as counter variable.

Scope variable

Hugo template has the limitation of scope variable, where you can’t set a outer variable from a local scope. This is actually a limitation of Go Template.

A variable’s scope extends to the “end” action of the control structure (“if”, “with”, or “range”) in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation.

You might expect outerResult=true; for the following example, but the correct answer is outerResult=false; as the setting of variable within the if scope is a local scope and doesn’t affect variable in the outer scope.

{{ $result := false }}
{{ if eq $result false }}
  {{ $result := true }}
  {{/* innerResult=true; */}}
  innerResult={{ $result }};
{{ end }}
{{/* outerResult=false; */}}
outerResult={{ $result }};

With scope variable limitation, you can’t count variable within a range loop as well. For the following example, innerCount will always be 1 (each loop is a new local scope) and outerCount is 0. innerCount can access $count variable of the outer scope, but it can’t change it from the inner scope.

{{ $count := 0 }}
{{ range .Site.Pages }}
  {{ $count := add $count 1 }}
  {{/* innerCount=1; */}}
  innerCount={{ $count }};
{{ end }}
{{/* outerCount=0; */}}
outerCount={{ $count }};

Use .Scratch

.Scratch acts as a “scratchpad” to allow for writable page-scoped or shortcode-scoped variables.

Both innerResult and outerResult will return true as expected based on the logic flow.

{{ $.Scratch.Set "result" false }}
{{ if eq ($.Scratch.Get "result") false }}
  {{ $.Scratch.Set "result" true }}
  {{/* innerResult=true; */}}
  innerResult={{ $.Scratch.Get "result" }};
{{ end }}
{{/* innerResult=true; */}}
outerResult={{ $.Scratch.Get "result" }};

count will increment correctly for the following case.

{{ $.Scratch.Set "count" 0 }}
{{ range .Site.Pages }}
  {{ $.Scratch.Add "count" 1 }}
  innerCount={{ $.Scratch.Get "count" }};
{{ end }}
outerCount={{ $.Scratch.Get "count" }};
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.