httpsrv provides view template rendering capabilities using Go's template engine. Templates are typically used in Web MVC's View (V) layer to render HTML pages.
Set template path when initializing Module:
func NewModule() *httpsrv.Module {
mod := httpsrv.NewModule("ui")
mod.SetTemplatePath("./views/ui")
return mod
}type User struct {
*httpsrv.Controller
}
func (c User) ProfileAction() {
user := map[string]interface{}{
"name": "John Doe",
"email": "john@example.com",
}
c.Data["user"] = user
c.Render("user/profile.tpl")
}Template file user/profile.tpl:
<!DOCTYPE html>
<html>
<head>
<title>User Profile</title>
</head>
<body>
<h1>{{.user.name}}</h1>
<p>Email: {{.user.email}}</p>
</body>
</html>// Render template from specific module
c.Render("user", "profile.tpl"){{.variable}}
{{.user.name}}
{{index .users 0}}{{if .user.is_admin}}
<p>Admin User</p>
{{else}}
<p>Regular User</p>
{{end}}{{range .users}}
<div>{{.name}}</div>
{{end}}{{with .user}}
<p>{{.name}} - {{.email}}</p>
{{end}}<!-- layouts/base.tpl -->
<!DOCTYPE html>
<html>
<head>
<title>{{block "title" .}}Default Title{{end}}</title>
</head>
<body>
<header>{{block "header" .}}Default Header{{end}}</header>
<main>
{{block "content" .}}{{end}}
</main>
<footer>{{block "footer" .}}Default Footer{{end}}</footer>
</body>
</html><!-- user/profile.tpl -->
{{template "layouts/base.tpl" .}}
{{define "title"}}User Profile{{end}}
{{define "header"}}
<nav>My App Navigation</nav>
{{end}}
{{define "content"}}
<h1>{{.user.name}}</h1>
<p>{{.user.email}}</p>
{{end}}{{.name | upper}} <!-- Uppercase -->
{{.name | lower}} <!-- Lowercase -->
{{.name | trim}} <!-- Trim whitespace -->
{{.name | htmlEscape}} <!-- HTML escape -->{{.price | format "%.2f"}} <!-- Format number -->
{{.count | add 10}} <!-- Add -->
{{.count | sub 5}} <!-- Subtract -->{{.created_at | date "2006-01-02"}}
{{.updated_at | datetime}}{{len .items}} <!-- Length -->
{{index .items 0}} <!-- Get by index -->Register custom template functions:
func init() {
httpsrv.GlobalService.Config.RegisterTemplateFunc("truncate", Truncate)
}
func Truncate(s string, length int) string {
if len(s) <= length {
return s
}
return s[:length] + "..."
}Use in template:
{{.description | truncate 100}}type User struct {
*httpsrv.Controller
}
func (c User) ListAction() {
users := []map[string]interface{}{
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"},
}
c.Data["users"] = users
c.Data["title"] = "User List"
c.Render("user/list.tpl")
}Template:
{{template "layouts/base.tpl" .}}
{{define "title"}}{{.title}}{{end}}
{{define "content"}}
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{{range .users}}
<tr>
<td>{{.id}}</td>
<td>{{.name}}</td>
<td>{{.email}}</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}func (c User) CreateAction() {
if c.Request.Method == "GET" {
c.Render("user/form.tpl")
return
}
name := c.Params.Value("name")
if name == "" {
c.Data["error"] = "Name is required"
c.Data["name"] = ""
c.Render("user/form.tpl")
return
}
// Create user...
}Template:
<form method="POST" action="/user/create">
{{if .error}}
<div class="error">{{.error}}</div>
{{end}}
<div>
<label>Name:</label>
<input type="text" name="name" value="{{.name}}">
</div>
<button type="submit">Submit</button>
</form>When c.AutoRender is true (default), system automatically searches for template:
type User struct {
*httpsrv.Controller
}
// System will look for: user/index.tpl
func (c User) IndexAction() {
c.Data["users"] = getUsers()
// No need to call c.Render()
}
// System will look for: user/profile.tpl
func (c User) ProfileAction() {
c.Data["user"] = getUser()
// No need to call c.Render()
}For Controller named User with Action ProfileAction:
- If
c.Render("user/profile.tpl")→ Look foruser/profile.tplin all template paths - If
c.Render("user", "profile.tpl")→ Look foruser/profile.tplin all template paths - If AutoRender → Look for
user/profile.tplin all template paths
Template search order:
- First template path set in Module
- Second template path set in Module
- ...
- Template files use
.tplextension by default - Template variables are passed through
c.Datamap - Use
{{block}}for template inheritance - Use
{{define}}to define reusable template blocks - All built-in Go template functions are available