Struggling with text/template, html/template best-practice

516 views
Skip to first unread message

Craig Mason-Jones

unread,
Apr 19, 2013, 12:27:51 AM4/19/13
to golan...@googlegroups.com
Hi all,

I am building a Go web app, and am struggling to determine best-practice for using html/template.

It seems from the example in text/template documentation that the 'recommended' way to use multiple templates to construct a page is along the lines of:

base, _ := templates.New("base").Parse(` The message is: {{template "content"}}`)

When I want to render my Hello World, I go:

temp, _ := base.Clone()
temp.Parse(` {{define "content"}}Hello, World{{end}} `)

temp.Execute(os.Stdout, nil)

But it seems to me that this involves a large quantity of parsing on each execution.

I can do this:

hello, _ := templates.New("hello").Parse("Hello, World")
goodbye,_ := templates.New("goodbye").Parse("Goodbye, cruel world!")

And now decide what I want the user to see:

var temp *template.Template
render, _ := base.Clone()
if !pinkFloyd {
  temp, _ = render.AddParseTree("content", hello.Tree)
} else {
  temp, _ = render.AddParseTree("content", goodbye.Tree)
}
render.Execute(os.Stdout, nil)

This seems a little better, but it still involves Cloning the base template, and it also involves using the text/template/parse/Tree in the Template type, which is meant to be internal to the template package.

Of course, all this would be unnecessary if I could just go:

data := make(map[string]string)
data["Content"] = "hello"
base,_ := templates.New("base").Parse(`{{define "hello"}}Hello, Word{{end}}  {{define "goodbye"}}Goodbye, cruel world!{{end}} The message is: {{template .Content}}`)
...

But that, alas, cannot be done (although if there is interest, I am prepared to write such a patch).

Am I using text/template (html/template actually, of course) correctly?

Is there a better way to do this?

All the best,
Craig

Dougx

unread,
Apr 19, 2013, 12:46:11 AM4/19/13
to golan...@googlegroups.com
You can easily do this:

t := templates.New("Id").Parse(whatever_source_string)
t.New("Id2").Parse(whatever_other_thing)
...
t.Execute(writer, data)

Any of the source strings may contain multiple {{define}} elements, so long as they all resolve at the end.
eg.

index file:
{{ define "Content" }}
stuff
{{ end }}

{{ define "Scripts" }}
other stuff
{{ end }}

{{ template "_layout" . }}

layout file:
{{ define "_layout" }}
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>Frag!</title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">

      <!-- Styles -->
      {{ template "_styles" . }}
    </head>
    <body>
      <!-- Header -->
      <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="navbar-inner">
          <div class="container-fluid">
            <a class="brand" href="{{ .Urls.FragmentIndex }}">Fragments</a>
          </div>
        </div>
      </div> <!-- /navbar -->

      <!-- Content -->
      <div class="container">
        {{ template "Content" . }}
      </div> <!-- /container -->

      <!-- Placed at the end of the document so the pages load faster -->
      <script src="http://code.jquery.com/jquery.js"></script>
      <script src="/assets/js/bootstrap.js"></script>
      {{ template "Scripts" . }}
    </body>
  </html>
{{ end }}

~
Doug.

Craig Mason-Jones

unread,
Apr 19, 2013, 1:37:22 AM4/19/13
to golan...@googlegroups.com
Ah, thank you Doug!

I think you've shown me how I should turn my example on its head:

baseTempl := `Message is: {{template "content" . }}`

hello, _ := templates.New("hello").Parse(` {{define "content"}}Hello World{{end}} {{template "base" . }}`)
hello.New("base").Parse(baseTempl)
goodbye, _ := templates.New("goodbye").Parse(`{{define "content"}}Goodbye, cruel world!{{end} {{template "base" .}}`)
goodbye.New("base").Parse(baseTempl)

Then

hello.Execute(w, data)

or

goodbye.Execute(w, data)

gives me exactly what I want: full templating goodness with a single parse-preparation phase.

Many thanks,
Craig

Craig Mason-Jones

unread,
Apr 20, 2013, 10:09:55 AM4/20/13
to golan...@googlegroups.com
Alas, on second thoughts, I'm not convinced this approach solves my problems. It works nicely in the single-template case, but what if I have a 'base' template that includes many different pieces, perhaps a content piece, and a 'user' piece, and a 'title' piece, and perhaps one or more 'content blocks'. I can't create different templates for each possible combination.

So far, I've been using an approach of creating each 'piece' as a separate template, then passing them into a base template as template.HTML pieces - the same approach demonstrated https://bitbucket.org/jzs/sketchground/src/4defb0a2ea64ed226680515efae4c5f8df5827a9/views.go?at=default.

But it is long-winded.

Any recommendations?

All the best,
Craig
Reply all
Reply to author
Forward
0 new messages