Views

Views And Layouts

Render embedded html/template views through layouts with escaped data and helpers.

By Guillermo Alvarez - Published - Updated

Embed views

The application embeds templates with ordinary Go embed.FS:

//go:embed views public
var Files embed.FS

var Views = lazyapp.MustSub(Files, "views")

Startup passes app.Views to lazyapp.New, which validates the renderer before requests are served.

Name controller views

Controller view paths follow the controller and action:

app/views/<controller>/<action>.html.tpl

Given PostsController#Index, the default view is:

app/views/posts/index.html.tpl

An action can set data and return nil:

func (c *PostsController) Index(_ http.ResponseWriter, _ *http.Request) error {
    c.Set("title", "Posts")
    c.Set("posts", c.posts.List())
    return nil
}

Read template data

Templates access values by the names passed to Set:

<h1>{{ .title }}</h1>

{{ range .posts }}
  <a href="/posts/{{ .Param }}">{{ .Title }}</a>
{{ end }}

The same data map is available to the controller view and the selected layout.

Compose a layout

The default layout is:

app/views/layouts/app.html.tpl

GoLazy executes the controller view first, then supplies the rendered HTML as .content:

<!doctype html>
<html>
  <head>
    <title>{{ .title }}</title>
  </head>
  <body>
    <main>{{ .content }}</main>
  </body>
</html>

Select another layout before rendering:

c.Layout("admin")
return nil

That resolves app/views/layouts/admin.html.tpl.

Register helpers

Application helpers are plain Go functions:

func RegisterHelpers() map[string]any {
    return map[string]any{
        "word_count": WordCount,
    }
}

Startup passes them to the app:

Helpers: lazyapp.Helpers{helpers.RegisterHelpers()},

Templates call helpers by their registered names:

{{ word_count .post.Body }} words

Keep escaping explicit

Go's html/template escapes ordinary values. Convert only trusted renderer output to template.HTML:

body, err := markdown.Convert(post.Body)
if err != nil {
    return err
}

c.Set("body", template.HTML(body))
return nil

Use Forms for form helpers and Hotwire Turbo for frame rendering.