Golang from Python

Go HTML Templates: Applying Data

The last post on structuring Go templates left out the main feature of templating: varying output. Let's look at my header.html again:

<html>
<head><title>{{ . }}</title></head>
<body>

{{ . }} means "put the value of . here." So, if you apply that template to the string "Index", it outputs <title>Index</title>. The same goes for structs; if you apply a template to a struct{Title string}, {{ .Title }} prints the title field.

There's one catch with using ., and the solution was deep enough in the docs that I missed it completely. Here's something that might look right, but isn't:

type Folder struct {
    Name string
    Files []string
}

f := Folder{"/root", []string{".bash_history", ".bashrc"}}

// It's not okay to ignore errors... unless you're a blog post.
tmpl, _ := template.New("t").Parse(
    `Contents of {{ .Name }}:
    {{ range _, $f := .Files }}
        {{ .Name }}/{{ $f }}
    {{ end }}
    `)
tmpl.Execute(os.Stdout, f)

This doesn't work, because . changes in context of a range, to refer to the current list element. The fix is easy, but it's buried a few pages down in the docs: $ always holds the original value of .. Here's the correct template (or run it on play.golang.org):

`Contents of {{ .Name }}:
{{ range .Files }}
    {{ $.Name }}/{{ . }}
{{ end }}`

here's another context in which . changes — when you invoke another template. Earlier, I applied index.html to a Go string with {{ template "header.html" "Index" }}. This works the same way as applying templates to values in Go code. For a small project, passing a string works great. For a larger project, I expect to pass a larger struct into my header and footer to include CSS and JavaScript files that are needed on each page, rather than a static list in the header.

In the next post, I'll look at functions and control flow. Go templates have a stricter separation between code and formatting, and it's the biggest departure from working with Jinja2.