My setup:
base.tmpl
{{define "base"}} ...basic hmtl boilerplate ...{{end}}
{{define "post"}}
{{.ID}} {{.Username}} etc...
{{if $.User.Admin}}
<...admin controls...>
{{end}}
{{end}}
index.tmpl
{{template "base" . }}
{{define "content"}}
Stuff......
{{range .Posts }}
{{template "post" . }}
{{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["index.tmpl"].Execute(rw, g); err != nil {
Log.Println("Error executing template", 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("templates/"+filename, "templates/base.tmpl"))
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:
Create a function (isAdmin
) that references the variable through closure:
template.New("test").Funcs(map[string]interface{}{
"isAdmin": 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.
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("test").Funcs(map[string]interface{}{
"pair": func(x, y interface{}) interface{} {
return struct { First, Second interface{} } { x, y }
},
}).Parse(src)
And you could use it like this:
{{range .Posts }}
{{template "post" pair $ . }}
{{end}}
Another option is to make a dict
function: Calling a template with several pipeline parameters