Template Parsing
Template Parsing
Beego uses Go’s built-in package html/template
as the template parser. Upon startup, it will compile and cache the templates into a map for efficient rendering.
Template Directory
The default template directory for Beego is views
. Template files can be put into this directory and Beego will parse and cache them automatically. However if the development mode is enabled, Beego parses templates every time without caching. Beego can only have one template directory which can be customized:
web.BConfig.WebConfig.ViewsPath = "myviewpath"
You can add alternative template directories by calling
web.AddViewPath("moreViews")
This will parse and cache template files in this directory and allow you to use them by setting ViewPath on a Controller:
this.ViewPath = "moreViews"
Setting a ViewPath to a directory which was not previously registered with AddViewPath() will fail with “Unknown view path”
Auto Rendering
You don’t need to render and output templates manually. Beego will call Render automatically after finishing the method. You can disable auto rendering in the configuration file or in main.go
if you don’t need it.
In configuration file:
autorender = false
In main.go:
web.BConfig.WebConfig.AutoRender = false
Template Tags
Go uses {{
and }}
as the default template tags. In the case that these tags conflict with other template tags as in AngularJS, we can use other tags. To do so,
In configuration file:
templateleft = <<<
templateright = >>>
Or, add these to the main.go:
web.BConfig.WebConfig.TemplateLeft = "<<<"
web.BConfig.WebConfig.TemplateRight = ">>>"
Template Data
Template gets its data from this.Data
in Controller. So for example if you need {{.Content}}
in the template, you need to assign it in the Controller first:
this.Data["Content"] = "value"
Different rendering types:
-
struct
Struct variable:
type A struct{ Name string Age int }
Assign value in the Controller:
this.Data["a"]=&A{Name:"astaxie",Age:25}
Render it in the template:
the username is {{.a.Name}} the age is {{.a.Age}}
-
map
Assign value in the Controller:
mp["name"]="astaxie" mp["nickname"] = "haha" this.Data["m"]=mp
Render it in the template:
the username is {{.m.name}} the username is {{.m.nickname}}
-
slice
Assign value in the Controller:
ss :=[]string{"a","b","c"} this.Data["s"]=ss
Render it in the template:
{{range $key, $val := .s}} {{$key}} {{$val}} {{end}}
Template Name
From version 1.6: this.TplNames is this.TplName
Beego uses Go’s built-in template engine, so the syntax is same as Go. To learn more about template see Templates.
You can set the template name in Controller and Beego will find the template file under the viewpath and render it automatically. In the config below, Beego will find add.tpl under admin and render it.
this.TplName = "admin/add.tpl"
Beego supports .tpl
and .html
file extensions by default. If you’re using other extensions, you must set it in the configuration first:
beego.AddTemplateExt("file_extension_you_need")
If TplName
is not set in the Controller while autorender
is enabled, Beego will use TplName
as below by default:
c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
It is Controller name + “/” + request method name + “.” + template extension. So if the Controller name is AddController
, request method is POST
and the default template extension is tpl
, Beego will render /viewpath/addcontroller/post.tpl
template file.
Layout Design
Beego supports layout design. For example, if in your application the main navigation and footer does not change and only the content part is different, you can use a layout like this:
this.Layout = "admin/layout.html"
this.TplName = "admin/add.tpl"
In layout.html
you must set a variable like this:
{{.LayoutContent}}
Beego will parse the file named TplName
and assign it to LayoutContent
then render layout.html
.
Beego will cache all the template files. You can also implement a layout this way:
{{template "header.html"}}
Logic code
{{template "footer.html"}}
LayoutSection
LayoutContent
is a little complicated, as it can include Javascript and CSS. Since in most situations having only one LayoutContent
is not enough, there is an attribute called LayoutSections
in Controller
. It allows us to set multiple section
in Layout
page and each section
can contain its own sub-template page.
layout_blog.tpl:
<!DOCTYPE html>
<html>
<head>
<title>Lin Li</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css">
{{.HtmlHead}}
</head>
<body>
<div class="container">
{{.LayoutContent}}
</div>
<div>
{{.SideBar}}
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
{{.Scripts}}
</body>
</html>
html_head.tpl:
<style>
h1 {
color: red;
}
</style>
scripts.tpl:
<script type="text/javascript">
$(document).ready(function() {
// bla bla bla
});
</script>
Here is the logic in the Controller:
type BlogsController struct {
web.Controller
}
func (this *BlogsController) Get() {
this.Layout = "layout_blog.tpl"
this.TplName = "blogs/index.tpl"
this.LayoutSections = make(map[string]string)
this.LayoutSections["HtmlHead"] = "blogs/html_head.tpl"
this.LayoutSections["Scripts"] = "blogs/scripts.tpl"
this.LayoutSections["Sidebar"] = ""
}
Another approach
We can also just specify the template the controller is going to use and let the template system handle the layout:
for example:
controller:
this.TplName = "blog/add.tpl"
this.Data["SomeVar"] = "SomeValue"
this.Data["Title"] = "Add"
template add.tpl:
{{ template "layout_blog.tpl" . }}
{{ define "css" }}
<link rel="stylesheet" href="/static/css/current.css">
{{ end}}
{{ define "content" }}
<h2>{{ .Title }}</h2>
<p> This is SomeVar: {{ .SomeVar }}</p>
{{ end }}
{{ define "js" }}
<script src="/static/js/current.js"></script>
{{ end}}
layout_blog.tpl:
<!DOCTYPE html>
<html>
<head>
<title>{{ .Title }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css">
{{ block "css" . }}{{ end }}
</head>
<body>
<div class="container">
{{ block "content" . }}{{ end }}
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
{{ block "js" . }}{{ end }}
</body>
</html>
Using block
action instead of template
allows us to have default block content and skipping blocks that we don’t need in every template (for example, if we don’t need css block in add.tpl
template - we will not define it and that won’t raise an error)
renderform
Define struct:
type User struct {
Id int `form:"-"`
Name interface{} `form:"username"`
Age int `form:"age,text,age:"`
Sex string
Intro string `form:",textarea"`
}
-
StructTag definition uses
form
as tag. It uses the same tags as Parse Form. There are three optional params separated by ‘,’:- The first param is
name
attribute of the form field. If empty, it will usestruct field name
as the value. - The second param is the form field type. If empty, it is assumed as
text
. - The third param is the tag of form field. If empty, it will use
struct field name
as the tag name.
- The first param is
-
If the
form
tag only has one value, it is thename
attribute of the form field. Except last value can be ignore all the other place must be separated by ‘,’. E.g.:form:",,username:"
-
To ignore a field there are two ways:
- The first way is to use lowercase for the field name in the struct.
- The second way is to set
-
as the value ofform
tag.
controller:
func (this *AddController) Get() {
this.Data["Form"] = &User{}
this.TplName = "index.tpl"
}
The param of Form must be a pointer to a struct.
template:
<form action="" method="post">
{{.Form | renderform}}
</form>
The code above will generate the form below:
Name: <input name="username" type="text" value="test"></br>
Age: <input name="age" type="text" value="0"></br>
Gender: <input name="Sex" type="text" value=""></br>
Intro: <input name="Intro" type="textarea" value="">