58

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() }}
Blacksad
  • 14,906
  • 15
  • 70
  • 81

3 Answers3

79

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.

aleb
  • 2,490
  • 1
  • 28
  • 46
tux21b
  • 90,183
  • 16
  • 117
  • 101
  • 4
    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. – Blacksad Apr 17 '12 at 22:55
  • 9
    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. – tux21b Apr 17 '12 at 23:00
  • And can I write {{ &. }} to get the address of . in my template ? – Blacksad Apr 17 '12 at 23:12
  • 3
    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 `*Person`s all the time. – tux21b Apr 17 '12 at 23:16
  • 1
    This is so much cleaner than [template.Funcs(FuncMap)](https://golang.org/pkg/text/template/#Template.Funcs)! – Tim Apr 28 '18 at 13:12
  • 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. – WeakPointer Aug 29 '21 at 14:16
47

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.

Usman Qadri
  • 479
  • 4
  • 2
-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 {
  ...
}
Sam Berry
  • 7,394
  • 6
  • 40
  • 58
  • 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. – Benjamin Carlsson Jul 01 '22 at 05:58