更新嵌套模板Golang

时间:2019-02-10 15:44:13

标签: go

我正在尝试动态更改内容。但是内容保持不变。似乎要获取第一个比赛。无论模板是什么。即使使用硬编码的文件名也不起作用。该代码可以正常工作,但是内容无法更改。

主要布局

{{define "layout"}}
    <html>
    <body>
        {{ template "content" }}
    </body>
    </html>
{{end}}

子模板1

{{ define "content" }}

<h1 style="color: red;">Page 1!</h1>

{{ end }}

子模板2

{{ define "content" }}

<h1 style="color: blue;">Page 2!</h1>

{{ end }}

执行代码

package main

import (
    "html/template"
    "net/http"
    "strings"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseGlob("templates/*.gohtml"))
}

func main() {
    http.HandleFunc("/", index)
    http.ListenAndServe(":8080", nil)
}

func index(w http.ResponseWriter, r *http.Request) {

    path := strings.Trim(r.URL.Path, "/")
    switch path {
    case "":
        path = ("index.gohtml")
    default:
        path = (path + ".gohtml")
    }

    err := tpl.ExecuteTemplate(w, "layout", path)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

我也尝试过在运气不佳之前执行ParseFiles。我在做什么错了?

3 个答案:

答案 0 :(得分:2)

我认为,在解析模板之后调整路径为时已晚。

什么可行(尽管我不确定这里是否是最优雅的解决方案)是使用AddParseTree方法:

  

AddParseTree为具有给定名称的模板添加解析树,并且   将其与t相关联。如果模板尚不存在,它将   创建一个新的。如果该模板确实存在,它将被替换。

根据您的情况,根据条件,您将先Parse相关的模板文件(子模板1或2),然后将AddParseTree添加到tpl,然后再进行操作执行它。

答案 1 :(得分:0)

最后我使它起作用,但是只有在不遵循手册的情况下。

解决方案第1部分

在模板中跳过{{define}}和{{end}}。奇怪...

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Go Web Programming</title>
  </head>
  <body>
    layout level
    {{ template "content" . }}
  </body>
</html>

在子模板中也是如此...

<h1 style="color: red;">Page 1!</h1>

解决方案第2部分

我找到了Eli提到的带有AddParsTree的代码片段,这是代码(简化后没有错误处理)

package main

import (
    "html/template"
    "net/http"
    "strings"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseGlob("templates/*.html"))
}

func main() {
    http.HandleFunc("/", index)
    http.ListenAndServe(":8080", nil)
}

func index(w http.ResponseWriter, r *http.Request) {

    path := strings.Trim(r.URL.Path, "/")
    switch path {
    case "":
        path = ("home.html")
    default:
        path = (path + ".html")
    }

    layout := tpl.Lookup("layout.html")
    layout, _ = layout.Clone()
    t := tpl.Lookup(path)
    _, _ = layout.AddParseTree("content", t.Tree)
    layout.Execute(w, "")

我真的不明白为什么我必须不遵守手册才能使它起作用。任何启发我的评论将不胜感激。

答案 2 :(得分:0)

我遇到了同样的问题,并以这种方式解决了:

这适用于 {{ define "content1" }}...{{ end }} 语法,但您必须为模板指定唯一名称:content1content2

我制作了一个用于处理模板内容的包。

package templates

import (
    "html/template"
    "log"
    "net/http"
)

var tmpls *template.Template

// LoadTemplates parses a template folder
func LoadTemplates(tmplPath string) {
    tmpls = template.Must(template.ParseGlob(tmplPath))
}

// ExecTmpl executes a template and writes it
func ExecTmpl(w http.ResponseWriter, tmpl string, data interface{}) {
    tmpls.ExecuteTemplate(w, tmpl, data)
}

// ExecTmplTree combines and executes two templates
func ExecTmplTree(w http.ResponseWriter, outer, inner string, data interface{}) {
    layout, err := tmpls.Lookup(outer).Clone()
    if err != nil || layout == nil {
        log.Fatal("ExecTmplTree: Could not get a copy of template", outer)
    }
    content, err := tmpls.Lookup(inner).Clone()
    if err != nil || content == nil {
        log.Fatal("ExecTmplTree: Could not get a copy of template", inner)
    }
    _, err = layout.AddParseTree("content", content.Tree)
    if err != nil {
        log.Fatal("ExecTmplTree: Templates could not be combined.")
    }
    layout.Execute(w, data)
}

然后我按如下方式调用函数(在 main.go 或其他地方):

// call first to load templates from the folder where your templates are stored
// you might need fit the file ending, too, I simply use .html for html-templates
func init() {
    templates.LoadTemplates("web/templates/*.html")
}

// write a basic template without nesting
func exampleHandler(w http.ResponseWriter, r *http.Request) {
    templates.ExecTmplTree(w, "content1", "messageForm", nil)
}

// write nested templates. here, index is the outer template
// and code is the inner
func indexHandler(w http.ResponseWriter, r *http.Request) {
    templates.ExecTmplTree(w, "layout", "content1", nil)
}