Reputation: 45
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
Upvotes: 0
Views: 6014
Reputation: 11828
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>
Upvotes: 4