0

I need to write a template where I first define some variables, and then use them in what will be generated from the template:

{{ if $value.Env.CADDY_URL }}
    {{ $url := $value.Env.CADDY_URL }}
{{ else }}
    {{ $url := printf "http://%s.example.info" $value.Name }}
{{ end }}

{{/* more template */}}
{{/* and here I would like to use $url defined above */}}
{{ $url }}

I get the error

undefined variable "$url"

Reading the documentation, I see that

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.

Does this mean that there are no global (or scoped on the whole template) variables? Or is there a way to define $url so that it can be reused later in the template?

WoJ
  • 27,165
  • 48
  • 180
  • 345

1 Answers1

1

Variables are scoped. You create the $url variable inside the {{if}} and {{else}} blocks, so they are not visible outside of those blocks.

Create the variable before the {{if}}, and use assignment = instead of declaration :=:

{{$url := ""}}
{{ if . }}
    {{ $url = "http://true.com" }}
{{ else }}
    {{ $url = "http://false.com" }}
{{ end }}

{{ $url }}

Testing it:

t := template.Must(template.New("").Parse(src))

fmt.Println(t.Execute(os.Stdout, true))
fmt.Println(t.Execute(os.Stdout, false))

Output (try it on the Go Playground):

http://true.com<nil>
http://false.com<nil>

Note: Modifying template variables with assignment was added in Go 1.11, so you need to build your app with Go 1.11 or newer. If you're using an older version, you cannot modify values of template variables.

Edit: I've found a duplicate: How do I assign variables within a conditional

You can mimic "changeable template variables" in earlier versions, see this question for examples: In a Go template range loop, are variables declared outside the loop reset on each iteration?

icza
  • 389,944
  • 63
  • 907
  • 827
  • Thank you. I tried this but then get `unexpected "=" in operand` on the line where the new value is assigned (which would be the (modified following your example) line `{{ $url = $value.Env.CADDY_URL }}`in my example above (after adding `{{ $url := "" }}` at the very top) – WoJ Jan 23 '20 at 18:47
  • I wonder if this is not related to https://github.com/golang/go/issues/10608. It may be the case since the program I use is 4 years old and it seems that the ability to overwrite variables in templates is new-ish. **EDIT: yes, this is the reason : https://github.com/jwilder/docker-gen/issues/299** – WoJ Jan 23 '20 at 18:50
  • Yes, modifying variables with assignment was added in Go 1.11, see the [release notes](https://golang.org/doc/go1.11#text/template). – icza Jan 23 '20 at 18:56