英文:
Cant execute template well in golang
问题
我正在尝试创建一些模板,但是我无法理解下面的问题:
为什么这个结构不起作用?
我有一个test.go文件:
package main
import (
"net/http"
"html/template"
"fmt"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//解析HTML
t, err := template.ParseFiles("test.html")
if err != nil {
fmt.Println(err)
}
Name := "MyName"
City := "MyCity"
t.ExecuteTemplate(w, "T1", Name)
t.ExecuteTemplate(w, "T2", City)
}
我还有一个test.html文件:
<html>
<head>
<title>Tamplates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Empty template: {{ `Some text` }} </p>
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
</body>
</html>
这是一个简单的示例,但不知何故它不起作用。
我尝试在h1标题之前添加字符串{{ define "T1" }} {{ . }} {{ end }}
和{{ define "T2" }} {{ . }} {{ end }}
,但结果只是网页上显示了字符串"MyName MyCity"。
英文:
I'm trying to create some templates and I just can't understand the next thing:
Why doesn't such construction work?
I've got test.go file:
package main
import (
"net/http"
"html/template"
"fmt"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//Parsing HTML
t, err := template.ParseFiles("test.html")
if err != nil {
fmt.Println(err)
}
Name := "MyName"
City := "MyCity"
t.ExecuteTemplate(w, "T1", Name)
t.ExecuteTemplate(w, "T2", City)
}
And I also have test.html:
<html>
<head>
<title>Tamplates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Empty template: {{ `"Some text"` }} </p>
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
</body>
</html>
It's easy example, but somewhy it doesnt work.
I tried adding strings {{ define "T1" }} {{ . }} {{ end }}
and {{ define "T2" }} {{ . }} {{ end }}
before h1 header, but it has resulted web page containing just string MyName MyCity
答案1
得分: 4
更新(2016年7月2日)
我将尽力解释为什么你的代码没有正确执行,并提供一个使用嵌套模板的正确解决方案。
在你的test.html文件中,你导入了两个模板:T1
和T2
,
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
这些模板应该在某个地方定义和编写,以便使用(可以将它们写在单独的文件中)。这是我发现的第一个问题,这是你如何定义它们的:
{{ define "T1" }} {{ . }} {{ end }}
{{ define "T2" }} {{ . }} {{ end }}
注意,{{.}}
是当前对象的简写形式,因此它将呈现调用ExecuteTemplate
函数时传递的任何数据。因此,为了解决这个问题,你应该指定要在每个模板中呈现的对象:
{{ define "T1" }} {{ .Name }} {{ end }}
{{ define "T2" }} {{ .City }} {{ end }}
现在,这是我发现的第二个问题。在你的TestHandler
函数中,你只是渲染了子模板,首先是T1
模板,然后是T2
模板:
t.ExecuteTemplate(w, "T1", Name)
t.ExecuteTemplate(w, "T2", City)
所以在任何时候,你都没有调用父模板。
下面是使用嵌套模板的示例。希望它能解决你对如何使用模板的疑问。
test.go文件
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//解析HTML
t, err := template.ParseFiles("test2.html", "t1.tmpl", "t2.tmpl")
if err != nil {
fmt.Println(err)
}
items := struct {
Name string
City string
}{
Name: "MyName",
City: "MyCity",
}
t.Execute(w, items)
}
test.html文件
<html>
<head>
<title>Templates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Empty template: {{ `"Some text"` }} </p>
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
</body>
</html>
t1.tmpl文件
{{ define "T1" }} {{ .Name }} {{ end }}
t2.tmpl文件
{{ define "T2" }} {{ .City }} {{ end }}
不使用子模板:
我对你的代码进行了一些更改,使其能够工作。我只是将Name
和City
变量作为结构集合发送到Execute方法中。请查看下面的代码:
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//解析HTML
t, err := template.ParseFiles("test.html")
if err != nil {
fmt.Println(err)
}
items := struct {
Name string
City string
}{
Name: "MyName",
City: "MyCity",
}
t.Execute(w, items)
}
并使用{{.Name}}
和{{.City}}
来访问这些导出字段。
<html>
<head>
<title>Tamplates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Name is {{.Name}} </p>
<p> City is {{.City}} </p>
</body>
</html>
英文:
Update (07/02/2016)
I'm gonna to try to explain as best I can why your code was not been executed properly and a proper solution using nested templates.
In your test.html file you were importing two templates: T1
and T2
,
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
those templates should be defined and write in somewhere to be used (a good place to be written could be in separate files). Here is the first issue that I found, this is how you defined them:
{{ define "T1" }} {{ . }} {{ end }}
{{ define "T2" }} {{ . }} {{ end }}
Note that the {{.}}
is a shorthand for the current object, so it will render whatever the data you pass when calling the ExecuteTemplate
function. So, to solve this issue, you should specify which object you want to render in each template:
{{ define "T1" }} {{ .Name }} {{ end }}
{{ define "T2" }} {{ .City }} {{ end }}
Now, here is the second issue that I found. In your TestHandler
function, you are just rendering the sub-templates, firstly the T1
template, and secondly the T2
template:
t.ExecuteTemplate(w, "T1", Name)
t.ExecuteTemplate(w, "T2", City)
so at no time, you are calling to the parent template.
Below you can find how it will look like using nested templates. I hope it will solve your doubt about how to use the templates.
test.go file
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//Parsing HTML
t, err := template.ParseFiles("test2.html", "t1.tmpl", "t2.tmpl")
if err != nil {
fmt.Println(err)
}
items := struct {
Name string
City string
}{
Name: "MyName",
City: "MyCity",
}
t.Execute(w, items)
}
test.html file
<html>
<head>
<title>Templates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Empty template: {{ `"Some text"` }} </p>
<p> Name is {{ template "T1" . }} </p>
<p> City is {{ template "T2" . }} </p>
</body>
</html>
t1.tmpl file
{{ define "T1" }} {{ .Name }} {{ end }}
t2.tmpl file
{{ define "T2" }} {{ .City }} {{ end }}
Without using sub-templates:
I did some changes in your code that made it work. I just send the 'Name' and 'City' variable in a struct collection to the Execute method. Check below:
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/test.html", TestHandler)
http.ListenAndServe(":8080", nil)
}
func TestHandler(w http.ResponseWriter, r *http.Request) {
//Parsing HTML
t, err := template.ParseFiles("test.html")
if err != nil {
fmt.Println(err)
}
items := struct {
Name string
City string
}{
Name: "MyName",
City: "MyCity",
}
t.Execute(w, items)
}
And using {{.Name}}
and {{.City}}
to access to those exported fields.
<html>
<head>
<title>Tamplates</title>
</head>
<body>
<h1>Testing some templates</h1>
<p> Name is {{.Name}} </p>
<p> City is {{.City}} </p>
</body>
</html>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论