Closed zeroactual closed 9 years ago
@zeroactual
r.SetHTMLTemplate(contact_template)
should be called at initialization. never inside a request since it is not thread safe.Btw, to make the data, you can use a map[string]type{ .. }
a struct, or use the built-in type gin.H
.
c.HTML(200, "base", gin.H{
"title": "Welcome",
"stuff": "this is some interesting stuff",
})
gin.H
is a map[string]interface{}
with some other facilities (it also works with XML) and more convenient since it is much shorter.
Okay it seems that switching {{template "content"}}
to {{template "content" . }}
Fixed the issue with the content not rendering. That only leaves the question of my usage of
r.SetHTMLTemplate(contact_template)
Since it's not thread safe then how do I tell the routes which template I want to render if I have multiple pages. Would I have to change {{template "content" .}}
to be {{.content}}
then render the partial I wanted to be there and pass the output of the partial in with the data?
@zeroactual if you have multiple templates, you have three options:
c.HTML()
and call template.ExecuteTemplate(c.Writer,...)
directly.I recommend you, the second choice!
As you can see: c.HTML can execute arbitrary code, it means you can use any setup and or render engine (like pongo2) and continue using the c.HTML() API.
Would I have to change {{template "content" .}} to be {{.content}} then render the partial I wanted to be there and pass the output of the partial in with the data?
That could be a different way to fix it! but you would be calling c.HTML(200, "base", gin.H{"content": "index"})
. Always "base". which is not nice.
templates := multitemplate.New()
templates.AddFromFiles("index",
template_dir + "Base.html",
partials_dir + "Navbar.html",
template_dir + "Index.html")
templates.AddFromFiles("contact",
template_dir + "Base.html",
partials_dir + "Navbar.html",
template_dir + "Contact.html")
router := gin.New()
router.HTMLRender = templates
but I would suggest you to move the HTML templates initialisation to a different method, so the code would be much cleaner:
router := gin.New()
router.HTMLRender = loadTemplates()
Okay this multitemplate looks pretty good but it looks like the version go get pulled down won't compile.
# github.com/gin-gonic/contrib/renders/multitemplate
/Users/wes/go/src/github.com/gin-gonic/contrib/renders/multitemplate/multitemplate.go:13: cannot use Render literal (type *Render) as type render.HTMLRender in assignment
/Users/wes/go/src/github.com/gin-gonic/contrib/renders/multitemplate/multitemplate.go:50: undefined: render.HTML
go get -u github.com/gin-gonic/gin go get -u github.com/gin-gonic/contrib/renders/multitemplate
? it works for me
Updating the dependencies fixed that problem. Right now it's returning a blank string.
What I have now for is
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/contrib/renders/multitemplate"
)
func main() {
templates := multitemplate.New()
templates.AddFromFiles("index",
"Base.html",
"Navbar.html",
"Index.html")
templates.AddFromFiles("contact",
"Base.html",
"Navbar.html",
"Contact.html")
router := gin.New()
router.HTMLRender = templates
router.GET("", func(c *gin.Context) {
c.HTML(200, "index", gin.H{
"title": "Home",
"stuff": "Interesting home stuff",
})
})
router.GET("/contact", func(c *gin.Context) {
c.HTML(200, "contact", gin.H{
"title": "Contact",
"stuff": "Interesting contact stuff",
})
})
router.Run(":8080")
}
Base.html
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.title}}</title>
</head>
<body>
{{template "navbar"}}
{{template "content"}}
</body>
</html>
{{end}}
Index.html
{{define "index"}}
<div>
Main content
{{.stuff}}
</div>
{{end}}
Contact.html
{{define "contact"}}
<div>
Contact content
{{.stuff}}
</div>
{{end}}
**Navbar.html***
{{define "navbar"}}
<div class="nav">This is a navbar</div>
{{end}}
I think that this part is causing me some of the problems
<body>
{{template "navbar"}}
{{template "content"}} <!--- not sure what this should be -->>
</body>
I had this same issue with that template design. I basically got rid of the 'base' template and just have a header/footer with all the html boilerplate included with all my other templates. It accomplishes the same thing, and it allows you to use SetHTMLTemplate with ParseGlob for loading templates as well.
For example:
{{define "tag"}}
{{template "header" .}}
Stuff
{{template "footer" .}}
{{end}}
and that can be called with:
c.HTML(200, "tag", data)
@zeroactual in your case, remove the {{define "base"}}
. Since it is the base, it can not have a defined name...
When using multitemplate, Gin runs: templates[name].Execute()
instead of template.ExecuteTemplate(name)
Also since Base.html is importing a template called: "content" why are you doing {{define "index"}}?
@zeroactual @techjanitor fix your templates.
Base.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.title}}</title>
</head>
<body>
{{template "navbar"}}
{{template "content" .}}
</body>
</html>
Index.html
{{define "content"}}
<div>
Main content
{{.stuff}}
</div>
{{end}}
Contact.html
{{define "content"}}
<div>
Contact content
{{.stuff}}
</div>
{{end}}
**Navbar.html***
{{define "navbar"}}
<div class="nav">This is a navbar</div>
{{end}}
RTFM :D This kind of issues are well defined in the standard library documentation.
This is what I changed:
{{ define "base" }}
{{ define "index }}
, {{ define "contact"}}
... with {{ define "content" }}
{{template "content"}}
with {{template "content" .}}
Thanks! That fixed it. It seems I got confused with how to do this when I was playing around with only one page and used a glob. The glob only allowed you to have one content block declared so I changed the names.
I was trying to RTM but I'm so used to Java that I think I was looking at this all the wrong way. Thanks again.
@manucorporat by using multitemplate
i have to declare all the multi templates outside of the request handle. It breaks the code organization. Using template.ExecuteTemplate(c.Writer,...)
and individual cache system might be the better way.
I'm having problems rendering templates. If all the template files are empty except the base template then there is no issue with the way my templates are currently. The problem is that I can't seem to figure out how to render a template with variables across multiple of the included templates such as in the Base layout and inside a navbar or content area.
I tried nested structs but have had no luck figuring out how to do this. Can anyone point me in the right direction?
Base.html
Index.html
What I'm trying to do when rendering the template