Remove 07.4.md spaces

This commit is contained in:
vCaesar
2017-06-09 22:30:28 +08:00
parent d96a99079d
commit 301cb8d0ab

View File

@@ -17,12 +17,12 @@ In Go, we have the `template` package to help handle templates. We can use funct
Example: Example:
```Go ```Go
func handler(w http.ResponseWriter, r *http.Request) { func handler(w http.ResponseWriter, r *http.Request) {
t := template.New("some template") // Create a template. t := template.New("some template") // Create a template.
t, _ = t.ParseFiles("tmpl/welcome.html", nil) // Parse template file. t, _ = t.ParseFiles("tmpl/welcome.html", nil) // Parse template file.
user := GetUser() // Get current user infomration. user := GetUser() // Get current user infomration.
t.Execute(w, user) // merge. t.Execute(w, user) // merge.
} }
``` ```
As you can see, it's very easy to use, load and render data in templates in Go, just as in other programming languages. As you can see, it's very easy to use, load and render data in templates in Go, just as in other programming languages.
@@ -40,32 +40,32 @@ We've just shown you how to parse and render templates. Let's take it one step f
In Go, Every field that you intend to be rendered within a template should be put inside of `{{}}`. `{{.}}` is shorthand for the current object, which is similar to its Java or C++ counterpart. If you want to access the fields of the current object, you should use `{{.FieldName}}`. Notice that only exported fields can be accessed in templates. Here is an example: In Go, Every field that you intend to be rendered within a template should be put inside of `{{}}`. `{{.}}` is shorthand for the current object, which is similar to its Java or C++ counterpart. If you want to access the fields of the current object, you should use `{{.FieldName}}`. Notice that only exported fields can be accessed in templates. Here is an example:
```Go ```Go
package main package main
import ( import (
"html/template" "html/template"
"os" "os"
) )
type Person struct { type Person struct {
UserName string UserName string
} }
func main() { func main() {
t := template.New("fieldname example") t := template.New("fieldname example")
t, _ = t.Parse("hello {{.UserName}}!") t, _ = t.Parse("hello {{.UserName}}!")
p := Person{UserName: "Astaxie"} p := Person{UserName: "Astaxie"}
t.Execute(os.Stdout, p) t.Execute(os.Stdout, p)
} }
``` ```
The above example outputs `hello Astaxie` correctly, but if we modify our struct a little bit, the following error emerges: The above example outputs `hello Astaxie` correctly, but if we modify our struct a little bit, the following error emerges:
```Go ```Go
type Person struct { type Person struct {
UserName string UserName string
email string // Field is not exported. email string // Field is not exported.
} }
t, _ = t.Parse("hello {{.UserName}}! {{.email}}") t, _ = t.Parse("hello {{.UserName}}! {{.email}}")
``` ```
This part of the code will not be compiled because we try to access a field that has not been exported. However, if we try to use a field that does not exist, Go simply outputs an empty string instead of an error. This part of the code will not be compiled because we try to access a field that has not been exported. However, if we try to use a field that does not exist, Go simply outputs an empty string instead of an error.
@@ -80,67 +80,67 @@ We know how to output a field now. What if the field is an object, and it also h
More examples: More examples:
```Go ```Go
package main package main
import ( import (
"html/template" "html/template"
"os" "os"
) )
type Friend struct { type Friend struct {
Fname string Fname string
} }
type Person struct { type Person struct {
UserName string UserName string
Emails []string Emails []string
Friends []*Friend Friends []*Friend
} }
func main() { func main() {
f1 := Friend{Fname: "minux.ma"} f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"} f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example") t := template.New("fieldname example")
t, _ = t.Parse(`hello {{.UserName}}! t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}} {{range .Emails}}
an email {{.}} an email {{.}}
{{end}} {{end}}
{{with .Friends}} {{with .Friends}}
{{range .}} {{range .}}
my friend name is {{.Fname}} my friend name is {{.Fname}}
{{end}} {{end}}
{{end}} {{end}}
`) `)
p := Person{UserName: "Astaxie", p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"}, Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}} Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p) t.Execute(os.Stdout, p)
} }
``` ```
### Conditions ### Conditions
If you need to check for conditions in templates, you can use the `if-else` syntax just like you do in regular Go programs. If the pipeline is empty, the default value of `if` is `false`. The following example shows how to use `if-else` in templates: If you need to check for conditions in templates, you can use the `if-else` syntax just like you do in regular Go programs. If the pipeline is empty, the default value of `if` is `false`. The following example shows how to use `if-else` in templates:
```Go ```Go
package main package main
import ( import (
"os" "os"
"text/template" "text/template"
) )
func main() { func main() {
tEmpty := template.New("template test") tEmpty := template.New("template test")
tEmpty = template.Must(tEmpty.Parse("Empty pipeline if demo: {{if ``}} will not be outputted. {{end}}\n")) tEmpty = template.Must(tEmpty.Parse("Empty pipeline if demo: {{if ``}} will not be outputted. {{end}}\n"))
tEmpty.Execute(os.Stdout, nil) tEmpty.Execute(os.Stdout, nil)
tWithValue := template.New("template test") tWithValue := template.New("template test")
tWithValue = template.Must(tWithValue.Parse("Not empty pipeline if demo: {{if `anything`}} will be outputted. {{end}}\n")) tWithValue = template.Must(tWithValue.Parse("Not empty pipeline if demo: {{if `anything`}} will be outputted. {{end}}\n"))
tWithValue.Execute(os.Stdout, nil) tWithValue.Execute(os.Stdout, nil)
tIfElse := template.New("template test") tIfElse := template.New("template test")
tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if part {{else}} else part.{{end}}\n")) tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if part {{else}} else part.{{end}}\n"))
tIfElse.Execute(os.Stdout, nil) tIfElse.Execute(os.Stdout, nil)
} }
``` ```
As you can see, it's easy to use `if-else` in templates. As you can see, it's easy to use `if-else` in templates.
@@ -184,105 +184,105 @@ Suppose we have an `emailDeal` template function associated with its `EmailDealW
Example: Example:
```Go ```Go
package main package main
import ( import (
"fmt" "fmt"
"html/template" "html/template"
"os" "os"
"strings" "strings"
) )
type Friend struct { type Friend struct {
Fname string Fname string
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
}
func EmailDealWith(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
} }
if !ok {
type Person struct { s = fmt.Sprint(args...)
UserName string
Emails []string
Friends []*Friend
} }
// find the @ symbol
func EmailDealWith(args ...interface{}) string { substrs := strings.Split(s, "@")
ok := false if len(substrs) != 2 {
var s string return s
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
// find the @ symbol
substrs := strings.Split(s, "@")
if len(substrs) != 2 {
return s
}
// replace the @ by " at "
return (substrs[0] + " at " + substrs[1])
} }
// replace the @ by " at "
return (substrs[0] + " at " + substrs[1])
}
func main() { func main() {
f1 := Friend{Fname: "minux.ma"} f1 := Friend{Fname: "minux.ma"}
f2 := Friend{Fname: "xushiwei"} f2 := Friend{Fname: "xushiwei"}
t := template.New("fieldname example") t := template.New("fieldname example")
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith}) t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith})
t, _ = t.Parse(`hello {{.UserName}}! t, _ = t.Parse(`hello {{.UserName}}!
{{range .Emails}} {{range .Emails}}
an emails {{.|emailDeal}} an emails {{.|emailDeal}}
{{end}} {{end}}
{{with .Friends}} {{with .Friends}}
{{range .}} {{range .}}
my friend name is {{.Fname}} my friend name is {{.Fname}}
{{end}} {{end}}
{{end}} {{end}}
`) `)
p := Person{UserName: "Astaxie", p := Person{UserName: "Astaxie",
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"}, Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"},
Friends: []*Friend{&f1, &f2}} Friends: []*Friend{&f1, &f2}}
t.Execute(os.Stdout, p) t.Execute(os.Stdout, p)
} }
``` ```
Here is a list of built-in template functions: Here is a list of built-in template functions:
```Go ```Go
var builtins = FuncMap{ var builtins = FuncMap{
"and": and, "and": and,
"call": call, "call": call,
"html": HTMLEscaper, "html": HTMLEscaper,
"index": index, "index": index,
"js": JSEscaper, "js": JSEscaper,
"len": length, "len": length,
"not": not, "not": not,
"or": or, "or": or,
"print": fmt.Sprint, "print": fmt.Sprint,
"printf": fmt.Sprintf, "printf": fmt.Sprintf,
"println": fmt.Sprintln, "println": fmt.Sprintln,
"urlquery": URLQueryEscaper, "urlquery": URLQueryEscaper,
} }
``` ```
## Must ## Must
The template package has a function called `Must` which is for validating templates, like the matching of braces, comments, and variables. Let's take a look at an example of `Must`: The template package has a function called `Must` which is for validating templates, like the matching of braces, comments, and variables. Let's take a look at an example of `Must`:
```Go ```Go
package main package main
import ( import (
"fmt" "fmt"
"text/template" "text/template"
) )
func main() { func main() {
tOk := template.New("first") tOk := template.New("first")
template.Must(tOk.Parse(" some static text /* and a comment */")) template.Must(tOk.Parse(" some static text /* and a comment */"))
fmt.Println("The first one parsed OK.") fmt.Println("The first one parsed OK.")
template.Must(template.New("second").Parse("some static text {{ .Name }}")) template.Must(template.New("second").Parse("some static text {{ .Name }}"))
fmt.Println("The second one parsed OK.") fmt.Println("The second one parsed OK.")
fmt.Println("The next one ought to fail.") fmt.Println("The next one ought to fail.")
tErr := template.New("check parse error with Must") tErr := template.New("check parse error with Must")
template.Must(tErr.Parse(" some static text {{ .Name }")) template.Must(tErr.Parse(" some static text {{ .Name }"))
} }
``` ```
Output: Output:
@@ -306,76 +306,76 @@ Here's a complete example, supposing that we have the following three files: `he
Main template: Main template:
```html ```html
{% raw %} {% raw %}
//header.tmpl //header.tmpl
{{define "header"}} {{define "header"}}
<html> <html>
<head> <head>
<title>Something here</title> <title>Something here</title>
</head> </head>
<body> <body>
{{end}} {{end}}
//content.tmpl //content.tmpl
{{define "content"}} {{define "content"}}
{{template "header"}} {{template "header"}}
<h1>Nested here</h1> <h1>Nested here</h1>
<ul> <ul>
<li>Nested usag</li> <li>Nested usag</li>
<li>Call template</li> <li>Call template</li>
</ul> </ul>
{{template "footer"}} {{template "footer"}}
{{end}} {{end}}
//footer.tmpl //footer.tmpl
{{define "footer"}} {{define "footer"}}
</body> </body>
</html> </html>
{{end}} {{end}}
//When using subtemplating make sure that you have parsed each sub template file, //When using subtemplating make sure that you have parsed each sub template file,
//otherwise the compiler wouldn't understand what to substitute when it reads the {{template "header"}} //otherwise the compiler wouldn't understand what to substitute when it reads the {{template "header"}}
{% endraw %} {% endraw %}
``` ```
Code: Code:
```Go ```Go
package main package main
import ( import (
"fmt" "fmt"
"os" "os"
"io/ioutil" "io/ioutil"
"text/template" "text/template"
) )
var templates *template.Template var templates *template.Template
func main() { func main() {
var allFiles []string var allFiles []string
files, err := ioutil.ReadDir("./templates") files, err := ioutil.ReadDir("./templates")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
}
for _, file := range files {
filename := file.Name()
if strings.HasSuffix(filename, ".tmpl") {
allFiles = append(allFiles, "./templates/"+filename)
}
}
templates, err = template.ParseFiles(allFiles...) #parses all .tmpl files in the 'templates' folder
s1, _ := templates.LookUp("header.tmpl")
s1.ExecuteTemplate(os.Stdout, "header", nil)
fmt.Println()
s2, _ := templates.LookUp("content.tmpl")
s2.ExecuteTemplate(os.Stdout, "content", nil)
fmt.Println()
s3, _ := templates.LookUp("footer.tmpl")
s3.ExecuteTemplate(os.Stdout, "footer", nil)
fmt.Println()
s3.Execute(os.Stdout, nil)
} }
for _, file := range files {
filename := file.Name()
if strings.HasSuffix(filename, ".tmpl") {
allFiles = append(allFiles, "./templates/"+filename)
}
}
templates, err = template.ParseFiles(allFiles...) #parses all .tmpl files in the 'templates' folder
s1, _ := templates.LookUp("header.tmpl")
s1.ExecuteTemplate(os.Stdout, "header", nil)
fmt.Println()
s2, _ := templates.LookUp("content.tmpl")
s2.ExecuteTemplate(os.Stdout, "content", nil)
fmt.Println()
s3, _ := templates.LookUp("footer.tmpl")
s3.ExecuteTemplate(os.Stdout, "footer", nil)
fmt.Println()
s3.Execute(os.Stdout, nil)
}
``` ```
Here we can see that `template.ParseFiles` parses all nested templates into cache, and that every template defined by `{{define}}` are independent of each other. They are persisted in something like a map, where the template names are keys and the values are the template bodies. We can then use `ExecuteTemplate` to execute the corresponding sub-templates, so that the header and footer are independent and content contains them both. Note that if we try to execute `s1.Execute`, nothing will be outputted because there is no default sub-template available. Here we can see that `template.ParseFiles` parses all nested templates into cache, and that every template defined by `{{define}}` are independent of each other. They are persisted in something like a map, where the template names are keys and the values are the template bodies. We can then use `ExecuteTemplate` to execute the corresponding sub-templates, so that the header and footer are independent and content contains them both. Note that if we try to execute `s1.Execute`, nothing will be outputted because there is no default sub-template available.
@@ -385,12 +385,12 @@ Templates in one set know each other, but you must parse them for every single s
Some times you want to contextualize templates, for instance you have a `_head.html`, you might have a header who's value you have to populate based on which data you are loading for instance for a todo list manager you can have three categories `pending`, `completed`, `deleted`. for this suppose you have an if statement like this Some times you want to contextualize templates, for instance you have a `_head.html`, you might have a header who's value you have to populate based on which data you are loading for instance for a todo list manager you can have three categories `pending`, `completed`, `deleted`. for this suppose you have an if statement like this
```html ```html
<title>{{if eq .Navigation "pending"}} Tasks <title>{{if eq .Navigation "pending"}} Tasks
{{ else if eq .Navigation "completed"}}Completed {{ else if eq .Navigation "completed"}}Completed
{{ else if eq .Navigation "deleted"}}Deleted {{ else if eq .Navigation "deleted"}}Deleted
{{ else if eq .Navigation "edit"}} Edit {{ else if eq .Navigation "edit"}} Edit
{{end}} {{end}}
</title> </title>
``` ```
Note: Go templates follow the Polish notation while performing the comparison where you give the operator first and the comparison value and the value to be compared with. The else if part is pretty straight forward Note: Go templates follow the Polish notation while performing the comparison where you give the operator first and the comparison value and the value to be compared with. The else if part is pretty straight forward
@@ -402,27 +402,27 @@ Typically we use a `{{ range }}` operator to loop through the context variable w
``` ```
We get the context object from the database as a struct object, the definition is as below We get the context object from the database as a struct object, the definition is as below
```Go ```Go
//Task is the struct used to identify tasks //Task is the struct used to identify tasks
type Task struct { type Task struct {
Id int Id int
Title string Title string
Content string Content string
Created string Created string
} }
//Context is the struct passed to templates //Context is the struct passed to templates
type Context struct { type Context struct {
Tasks []Task Tasks []Task
Navigation string Navigation string
Search string Search string
Message string Message string
} }
//present in database package //present in database package
var task []types.Task var task []types.Task
var context types.Context var context types.Context
context = types.Context{Tasks: task, Navigation: status} context = types.Context{Tasks: task, Navigation: status}
//This line is in the database package where the context is returned back to the view. //This line is in the database package where the context is returned back to the view.
``` ```
We use the task array and the Navigation in our templates, we saw how we use the Navigation in the template, We use the task array and the Navigation in our templates, we saw how we use the Navigation in the template,
we'll see how we'll use the actual task array in our template. we'll see how we'll use the actual task array in our template.
@@ -434,29 +434,29 @@ start with the Range operator, then we can give any member of that struct as `{{
Title and a Content, (please note the capital T and C, they are exported names and they need to be capitalised unless you Title and a Content, (please note the capital T and C, they are exported names and they need to be capitalised unless you
want to make them private). want to make them private).
```Go ```Go
{{ range .Tasks }} {{ range .Tasks }}
{{ .Title }} {{ .Title }}
{{ .Content }} {{ .Content }}
{{ end }} {{ end }}
``` ```
This block of code will print each title and content of the Task array. Below is a full example from github.com/thewhitetulip/Tasks home.html template. This block of code will print each title and content of the Task array. Below is a full example from github.com/thewhitetulip/Tasks home.html template.
```html ```html
<div class="timeline"> <div class="timeline">
{{ if .Tasks}} {{range .Tasks}} {{ if .Tasks}} {{range .Tasks}}
<div class="note"> <div class="note">
<p class="noteHeading">{{.Title}}</p> <p class="noteHeading">{{.Title}}</p>
<hr> <hr>
<p class="noteContent">{{.Content}}</p> <p class="noteContent">{{.Content}}</p>
</ul> </ul>
</span> </span>
</div> </div>
{{end}} {{else}} {{end}} {{else}}
<div class="note"> <div class="note">
<p class="noteHeading">No Tasks here</p> <p class="noteHeading">No Tasks here</p>
<p class="notefooter"> <p class="notefooter">
Create new task<button class="floating-action-icon-add" > here </button> </p> Create new task<button class="floating-action-icon-add" > here </button> </p>
</div> </div>
{{end}} {{end}}
``` ```
## Summary ## Summary