我正试图在Go中使用html/template
嵌入模板。我非常喜欢无逻辑模板设计,我对它能够按预期安全地逃避事物的能力充满信心(有时其他模板库也会出错)。
{{ template checkoutJS }}
并通过设置{{ define checkoutJS }}https://path.to/extra.js {{ end }}
添加一些每页JS。
我希望能够在我的HTTP处理程序中说renderTemplate(w, "template_name.tmpl", data)
,其中data
是一个map [string] interface {},其中包含我希望填写的字符串或结构。
到目前为止,这是代码:
base.tmpl
{{ define "base" }}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ template "title" . }}</title>
</head>
<body>
<div id="sidebar">
...
</div>
{{ template "content" }}
<div id="footer">
...
</div>
</body>
</html>
create_listing.tmpl
{{ define "title" }}Create a New Listing{{ end }}
{{ define "content" }}
<form>
...
</form>
{{ end }}
login_form.tmpl
{{ define "title" }}Login{{ end }}
{{ define "content" }}
<form>
...
</form>
{{ end }}
main.go
package main
import (
"fmt"
"github.com/gorilla/mux"
"html/template"
"log"
"net/http"
)
// Template handling shortcuts
var t = template.New("base")
func renderTemplate(w http.ResponseWriter, tmpl string, data map[string]interface{}) {
err := t.ExecuteTemplate(w, tmpl, data)
// Things will be more elegant than this: just a placeholder for now!
if err != nil {
http.Error(w, "error 500:"+" "+err.Error(), http.StatusInternalServerError)
}
}
func monitorLoginForm(w http.ResponseWriter, r *http.Request) {
// Capture forms, etc.
renderTemplate(w, "login_form.tmpl", nil)
}
func createListingForm(w http.ResponseWriter, r *http.Request) {
// Grab session, re-populate form if need be, generate CSRF token, etc
renderTemplate(w, "create_listing.tmpl", nil)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/monitor/login", monitorLoginForm)
http.Handle("/", r)
log.Fatal(http.ListenAndServe(":8000", nil))
}
func init() {
fmt.Println("Starting up.")
_, err := t.ParseGlob("templates/*.tmpl")
if err != nil {
log.Fatal("Error loading templates:" + err.Error())
}
}
这个编译,但我从我的处理程序回来一个空的响应。请注意,我没有第二个处理程序的路由:该代码只是为了显示我想如何从处理程序调用{{1}}。
答案 0 :(得分:2)
您无法使用当前的go模板包执行所需操作。模板没有继承,因此模板中没有命名块。定义页眉和页脚模板更常见,而不是定义基本模板。然后,在您的页面模板中,明确包含您希望它们前往的位置。
我相信,另一个解决方案是拥有一个两阶段模板阶段。第一种是为基本模板的所有块编译模板。这些会被添加到地图中,然后发送到基本模板以供收录。
答案 1 :(得分:1)
这非常不明显,我不知道他们为什么这样做
ParseGlob返回一个你丢弃的值,但你需要保留它;它是您需要调用的模板对象,因此您的代码应如下所示:
func init() {
fmt.Println("Starting up.")
t, err := template.ParseGlob("templates/*.tmpl")
if err != nil {
log.Fatal("Error loading templates:" + err.Error())
}
}
该方法的文档(与上面使用的库函数相反)有点不清楚,因为它表示它将模板与调用该方法的模板对象相关联,但它也返回指向a的指针模板对象,如果它像宣传的那样工作就不需要做。有趣!