Go template functions
12 November 2024
Recently I wanted to add a function to the data object for a Go template which would allow me to generate some parts dynamically.
Here's what my first attempt looked like. For a template like this:
<p>The number is {{.Number}}</p>
<p>{{.CreateGreeting "Dave"}}</p>
I tried to use it like this:
type Data struct {
Number int
}
func (d *Data) CreateGreeting(name string) template.HTML {
return template.HTML("Hello, <b>" + name + "</b>")
}
func main() {
tmpl := template.Must(template.ParseFiles("template.gotmpl"))
data := Data{
Number: 4,
}
var buff bytes.Buffer
if err := tmpl.Execute(&buff, data); err != nil {
log.Fatal(err)
}
fmt.Println(buff.String())
}
Template execution failed with an error, which was a little surprising to me as a Go newbie. The CreateGreeting function is right there!
template: template.gotmpl:2:5: executing "template.gotmpl" at <.CreateGreeting>: can't evaluate field CreateGreeting in type main.Data
The issue at hand is that I've used a pointer receiver for my Data object but I have passed it by value into the template. One possible fix is to pass the data by value to the helper function.
func (d Data) CreateGreeting(name string) template.HTML { // <-- "d Data", no pointer
return template.HTML("Hello, <b>" + name + "</b>")
}
If I want to avoid the value receiver however, it turns out another possibility is to simply pass in a pointer in the first place.
if err := tmpl.Execute(&buff, &data); err != nil { // <-- now using &data
log.Fatal(err)
}
This also gives me the output I expect:
<p>The number is 4</p> <p>Hello, <b>Dave</b></p>