Golang模板中的全局点在给定值的范围内的模板中。

huangapple go评论76阅读模式
英文:

Golang template global dot within a template that's given a value from range

问题

我的设置:

base.tmpl

{{define "base"}} ...基本的HTML模板...{{end}}
{{define "post"}}
    {{.ID}} {{.Username}} 等...
    {{if $.User.Admin}}
        <...管理员控制...>
    {{end}}
{{end}}

index.tmpl

{{template "base" .}}
{{define "content"}}
    内容......
    {{range .Posts}}
        {{template "post" .}}
    {{end}}
{{end}}

但是我得到了以下错误信息:

$.User.Admin不是db.Post的字段

在没有给定的模板中,如何从“全局”点值中获取值?$.显然不起作用。

我之前只是在范围内使用了post,但我添加了一个新页面来查看单个帖子,并且不希望单独更新每个显示帖子的区域。

更新:模板的执行方式如下:

func Index(rw http.ResponseWriter, req *http.Request) {
    g := GetGlobal(rw, req) // 获取已登录用户信息,添加分支/版本信息等
    ... 从数据库获取帖子 ...
    if err := Templates["index.tmpl"].Execute(rw, g); err != nil {
	    Log.Println("执行模板时出错", err.Error())
    }
}

Global结构如下:

type Global struct {
    User     db.User
    Users    []db.User
    EditUser db.User
    Session  *sessions.Session
    Error    error
    Posts    []db.Post
    Post     db.Post

    DoRecaptcha bool
	Host        string
    Version     string
    Branch      string
}

模板加载方式如下:

Templates[filename] = template.Must(template.ParseFiles("templates/"+filename, "templates/base.tmpl"))
英文:

My setup:

base.tmpl

{{define &quot;base&quot;}} ...basic hmtl boilerplate ...{{end}}
{{define &quot;post&quot;}}
    {{.ID}} {{.Username}} etc... 
    {{if $.User.Admin}}
        &lt;...admin controls...&gt;
    {{end}}
{{end}}

index.tmpl

{{template &quot;base&quot; . }}
{{define &quot;content&quot;}}
    Stuff......
    {{range .Posts }}
        {{template &quot;post&quot; . }}
    {{end}}
{{end}}

But I get
>$.User.Admin is not a field of db.Post

How can I get the values from the "global" dot value within a template that isn't given it? $. clearly doesn't work.

I was just having the post within the range, but I added a new page to view individual posts and would like to not update each area that posts are displayed individually.

Update: Templates are executed like so

func Index(rw http.ResponseWriter, req *http.Request) {
    g := GetGlobal(rw, req) // Gets logged in user info, adds branch/version info etc
    ... Get posts from the DB ...
    if err := Templates[&quot;index.tmpl&quot;].Execute(rw, g); err != nil {
	    Log.Println(&quot;Error executing template&quot;, err.Error())
    }
}

The Global struct looks like:

type Global struct {
    User     db.User
    Users    []db.User
    EditUser db.User
    Session  *sessions.Session
    Error    error
    Posts    []db.Post
    Post     db.Post

    DoRecaptcha bool
	Host        string
    Version     string
    Branch      string
}

Templates are loaded like so:

Templates[filename] = template.Must(template.ParseFiles(&quot;templates/&quot;+filename, &quot;templates/base.tmpl&quot;))

答案1

得分: 4

调用模板会创建一个新的作用域:

> 模板调用不会继承调用点的变量。

所以你有三个选项:

  1. 在帖子中添加对父级的引用(就像你在最后一条评论中说的那样)。

  2. 创建一个通过闭包引用变量的函数(isAdmin):

     template.New("test").Funcs(map[string]interface{}{
         "isAdmin": func() bool {
             return true // 你可以在这里获取它
         },
     }).Parse(src)
    

    这种方法的缺点是你需要每次解析模板。

  3. 创建一个新的函数,可以构造一个带有对父级的引用的帖子,而无需修改原始数据。例如:

     template.New("test").Funcs(map[string]interface{}{
         "pair": func(x, y interface{}) interface{} {
             return struct { First, Second interface{} } { x, y }
         },
     }).Parse(src)
    

    然后你可以像这样使用它:

     {{range .Posts }}
         {{template "post" pair $ . }}
     {{end}}
    

    另一个选项是创建一个 dict 函数:https://stackoverflow.com/questions/18276173/calling-a-template-with-several-pipeline-parameters/18276968#18276968

英文:

Invoking a template creates a new scope:

> A template invocation does not inherit variables from the point of its invocation.

So you have three options:

  1. Add a reference to the parent in the post (as you said you're doing in your last comment)

  2. Create a function (isAdmin) that references the variable through closure:

     template.New(&quot;test&quot;).Funcs(map[string]interface{}{
         &quot;isAdmin&quot;: func() bool {
             return true // you can get it here
         },
     }).Parse(src)
    

The downside of this approach is you have to parse the template every time.
3. Create a new function which can construct a post that has a reference to the parent without having to modify the original data. For example:

    template.New(&quot;test&quot;).Funcs(map[string]interface{}{
        &quot;pair&quot;: func(x, y interface{}) interface{} {
            return struct { First, Second interface{} } { x, y }
        },
    }).Parse(src)

And you could use it like this:

    {{range .Posts }}
        {{template &quot;post&quot; pair $ . }}
    {{end}}

Another option is to make a dict function: https://stackoverflow.com/questions/18276173/calling-a-template-with-several-pipeline-parameters/18276968#18276968

huangapple
  • 本文由 发表于 2015年4月14日 05:14:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/29615224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定