Call a method from a Go template
Asked Answered
M

3

62

Let's say I have

type Person struct {
  Name string
}
func (p *Person) Label() string {
  return "This is " + p.Name
}

How can I use this method from a html/template ? I would need something like this in my template:

{{ .Label() }}
Monkey answered 17/4, 2012 at 22:32 Comment(0)
L
84

Just omit the parentheses and it should be fine. Example:

package main

import (
    "html/template"
    "log"
    "os"
)

type Person string

func (p Person) Label() string {
    return "This is " + string(p)
}

func main() {
    tmpl, err := template.New("").Parse(`{{.Label}}`)
    if err != nil {
        log.Fatalf("Parse: %v", err)
    }
    tmpl.Execute(os.Stdout, Person("Bob"))
}

According to the documentation, you can call any method which returns one value (of any type) or two values if the second one is of type error. In the later case, Execute will return that error if it is non-nil and stop the execution of the template.

Linell answered 17/4, 2012 at 22:43 Comment(6)
Thanks, it works ! I had tried it, but the receiver of my method was *Person instead of Person. So it does not work with pointer receivers, that seems to be the catch.Monkey
It also work with pointer receivers. But please note that when you have a func (p *Person) Label() only values of the type *Person will have a Label() method. You can not call that method on a Person, since you haven't defined it.Linell
And can I write {{ &. }} to get the address of . in my template ?Monkey
No, you can't. But if you define your methods on a *Person (which is required if you want to change its attribute), just use *Persons all the time.Linell
This is so much cleaner than template.Funcs(FuncMap)!Lauricelaurie
I also found that when I have a method that takes a pointer as an argument, the template let's me pass nil as the argument to the method. Nice.Outsell
P
49

You can even pass parameters to function like follows

type Person struct {
  Name string
}
func (p *Person) Label(param1 string) string {
  return "This is " + p.Name + " - " + param1
}

And then in the template write

{{with person}}
    {{ .Label "value1"}}
{{end}}

Assuming that the person in the template is a variable of type Person passed to Template.

Pickford answered 6/8, 2013 at 1:0 Comment(2)
how do you pass multiple arguments?Sufficient
@Sufficient simply {{ .Label "value1" "value2"}}Thermaesthesia
O
-2

Unsure if it is incompetence on my part or a recent change in Go templates, but I am unable to access functions on the data struct passed into Execute. Always receive "can't evaluate field" error.

I was able to get this working by using FuncMap instead.

Example:

temp := template.New("templatename.gohtml")
temp.Funcs(
    template.FuncMap{
        "label": Label,
    },
)
temp, err := temp.ParseFiles(
    "templatename.gohtml",
)
if err != nil {
    log.Fatal("Error parsing template", err)
}

err = temp.Execute(os.Stdout, nil)

In template:

{{label "the label"}}

Label func:

func Label(param string) string {
  ...
}
Osmosis answered 23/11, 2021 at 17:1 Comment(1)
As pointed out by tux21b, make sure your template has a pointer if the method is defined on a pointer, and a non-pointer if the method is defined on a non-pointer.Formfitting

© 2022 - 2024 — McMap. All rights reserved.