4

The Goal: using multiple templates in an HTTP server where I want to change newlines into <br/> tags on some strings.

A stripped down example:

I have two templates a.tmpl and b.tmpl which look like this:

Template a {{dosomething}}

(and similar the other template). Both reside in a directory called templates. I believe that I need to create a function to do the \n -> <br /> replacement (dosomething above).

This is my (non working) sample code:

package main

import (
    "log"
    "text/template"
)

func main() {
    // funcMap := template.FuncMap{
    //  "dosomething": func() string { return "done something" },
    // }

    templates, err := template.ParseGlob("templates/*.tmpl")
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("%#v", templates)

}

The error message is:

2013/03/04 20:08:19 template: a.tmpl:1: function "dosomething" not defined
exit status 1

which makes sense, because during the parsing time, the function dosomething is not known.

  1. How can I use my function in multiple templates? Is the answer to this question here on so the only way to go?
  2. Is this the correct approach? Remember, I'd like to change the text on some strings, similar to the title example in the documentation (http://golang.org/pkg/text/template/#FuncMap - Example (Func))?
  3. How do I access b.tmpl in the following code:

    package main
    
    import (
        "log"
        "text/template"
    )
    
    func main() {
        funcMap := template.FuncMap{
            "dosomething": func() string { return "done something" },
        }
    
        t, err := template.New("a.tmpl").Funcs(funcMap).ParseGlob("templates/*.tmpl")
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("%#v", t)
    }
    
Community
  • 1
  • 1
topskip
  • 16,207
  • 15
  • 67
  • 99

1 Answers1

3

Your last snippet of code looks about right to me.

To render b.tmpl, just call

t.ExecuteTemplate(w, "b.tmpl", data)

You can access a.tmpl the same way; I would recommend doing this for consistency, rather than setting the name to "a.tmpl" in the call to New.

andybalholm
  • 15,395
  • 3
  • 37
  • 41
  • I don't quite understand the second part of your answer - how to access `a.tmpl` the same way. I need to call `Funcs(funcMap)` something like "inbetween" a new and `ParseGlob(...)` – topskip Mar 04 '13 at 21:29
  • @topskip I meant that you should render template a by calling t.ExecuteTemplate(w, "a.tmpl", data) rather than by calling t.Execute(w, data). That way the two templates are treated equally. Then you can give the set of all the templates a better name than "a.tmpl". – andybalholm Mar 04 '13 at 22:57
  • 2
    This is what I have now: `t, err := template.New("").Funcs(funcMap).ParseGlob("templates/*.tmpl")` and then `t.ExecuteTemplate(os.Stdout, "b.tmpl", "hello")` - this works fine. Same with the other template. Thanks! – topskip Mar 05 '13 at 09:29
  • Thank you, applying Funcs to multiple templates isn't documented anywhere – Drew Dec 29 '13 at 05:27
  • So, what's the point of `template.New("")`? Does the parameter for `template.New` not matter if we use `t.ExecuteTemplate` instead of `t.Execute`? – 425nesp Dec 06 '14 at 17:41
  • 1
    With template.New, you're just creating a base template—a container to hold the other templates. So, right, the name doesn't really matter. I do `template.New("root")`. – andybalholm Dec 06 '14 at 17:58
  • Worth pointing out also, as done in @topskip's example, you have to run `.Funcs(..)` before any `.Parse*(..)`, otherwise the template will not be aware of the functions. – Victor Häggqvist Feb 25 '17 at 16:15