Simple Go templates rendering (wut = web utils).
wutrender uses Go's html/template package to render templates.
// main.go
package main
import (
"github.com/8protons/wutrender"
)
func main() {
// Init default Renderer with default options
wutrender.Init()
// Init default Renderer with custom options
wutrender.Init(wutrender.Options{
Directory: "app/templates",
Layout: "layout",
})
// return (*bytes.Buffer, error)
wutrender.HTML("sessions/new", map[string]interface{}{ "hello": "world" })
}
// ..
// WriteHTML is an easy way to write to ResponseWriter
func IndexHandler(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{}
data["counter"] = 5
wutrender.WriteHTML(w, 200, "hello", data)
}
// ..
<!-- templates/hello.html.tmpl -->
<h2>Hello {{.}}!</h2>
wutrender.Renderer
can be configurated by several options:
// ...
wutrender.New(wutrender.Options{
Directory: "templates", // Specify a path to a folder which contains templates
Layout: "layout", // Specify a layout template
Extensions: []string{".tmpl"}, // Specify extensions for templates
Delims: render.Delims{"{{{", "}}}"}, // Override default delimiters
Funcs: []template.FuncMap{AppHelpers}, // Specify helper function
})
// ...
By default the wutrender.Renderer
will load templates with *.tmpl extension from the "templates" directory.
It uses filepath/filename.{format}.{extension}
scheme to distinguish folders and content formats.
For example, this templates folder:
templates/
|
|__ users/
| |
| |__ new.html.tmpl
| |
| |__ edit.html.tmpl
| |
| |__ update.js.tmpl
| |
| |__ user.json.tmpl
|
|__ layout.html.tmpl
Will provide the following templates:
users/new.html
users/edit.html
users/update.js
users/user.json
layout.html
We can render it as:
// HTML format function - render "users/new.html"
wutrender.HTML("users/new", nil)
wutrender.HTML("users/edit", map[string]interface{}{"answer": 42})
// write HTML to ResponseWriter
wutrender.WriteHTML(w, 200, "users/new", nil)
// JS format function - render "users/update.js"
wutrender.JS("users/update", nil)
// or with standalone Render function
wutrender.RenderFormat("js", "users/update", nil)
wutrender.RenderFormat("html", "users/new", nil)
It may be useful when you want to render a JavaScript file back to client:
// templates/users/update.js.tmpl
jGrowl("User sucessfuly updated");
$('.user-form').hide();
or even if you want to render a complex JSON file:
{{/* templates/users/user.json.tmpl */}}
{
"id": "{{ .User.Id }}",
"profile": {
"name": "{{ .User.Name }}"
}
}
wutrender.Renderer
uses wutenv package to detect current application environment (by GO_ENV or GO_FLAVOR):
// Recompile template
if wutenv.IsDev {
tc = r.compile()
} else {
tc, _ = r.t.Clone()
}
In development mode, it will recompile all templates each time, so no need to restart server if something's changed.
In production mode, it will just use Clone()
function from html/template
package.
Everytime we want to render a template - we create a copy.
wutrender.Renderer
has the Copy()
method which return *TemplateCopy
struct (it provides all rendering functions - HTML, JS, WriteHTML, etc.).
This guarantees cleanness of the source templates and also allows us to use per template functions and, for example, different layouts:
wutrender.Copy().SetFuncs(PerTemplateFuncs).SetLayout("company").HTML("hello", nil)
wutrender.HTML(...)
method does this, for example: DefaultRenderer.Copy().HTML(...)
wutrender
has the yield
function for layouts which render current template:
// ...
wutrender.Init(wutrender.Options{
Layout: "layout",
})
// ...
<!-- templates/layout.html.tmpl -->
<html>
<head>
<title>Layout |::| wut!</title>
</head>
<body>
<!-- Render the current template here -->
{{ yield }}
</body>
</html>
partial
function takes name
argument, transforms it to {filepath}/_{filename}.html
and renders this template with the provided binding.
Example: users/user
becomes users/_user.html
Binding can be:
- Empty:
{{ partial "users/user" }}
- Simple object:
{{ partial "users/user" . }}
(full binding from the parent template) orpartial "users/user" .User
(one object from the parent template) - Key-Value pairs:
{{ partial "users/user" "user" .User "isEdit" true }}
- first argument is a string key, second is an interface{} value (idea from Gorilla Mux - URL)
<div class="container">
<!-- Render "users/_user.html" template here without binding -->
{{ partial "users/user" }}
<!-- Render "users/_user.html" template here and pass current binding to it -->
{{ partial "users/user" . }}
<!-- Render "users/_user.html" template here and pass a map binding: {user: .user, isEdit: true} -->
{{ partial "users/user" "user" .User "isEdit" true }}
</div>
Loop example:
<div class="container">
<!-- Example partial rendering with loop -->
{{ range .channels }}
{{ partial "channels/channel" . }}
{{ end }}
</div>
<!-- templates/channels/_channel.html.tmpl -->
<div class="channel">
{{ .Name }}
</div>