gin
gin copied to clipboard
Gin HTML rendering documentation example incorrect
Hi, looking at the page:
https://gin-gonic.com/docs/examples/html-rendering/
specifically this example:
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.Run(":8080")
}
When you do
router.LoadHTMLGlob("templates/**/*")
This looks for any files within the templates directory and any subsequent subdirectories.
However these templates/files are availble using their filename and NOT the path.
For example given the following directory structure
- template/ /base /file1.html /other /file2.html
When using using these templates in code
func fileOne(c *gin.Context) {
c.HTML(http.StatusOK, "base/file1.html", nil)
}
you CANNOT use the path "base/file1.html" you have to just call the filename (see example below)
func fileOne(c *gin.Context) {
c.HTML(http.StatusOK, "file1.html", nil)
}
I realised this when running the gin app you get the following output on console
[GIN-debug] Loaded HTML Templates (14): - file1.html - file2.html
Which basically means that Gin loads the files and makes them available, however when you want to use those file you just call the filename. The example shows that you call the base path etc.. but this does not work.
This also means you cannot have templates with the same filename.
Do you wrap your html template in the {{define <template-path>}} - {{end}} block?
Here is my code try to reproduce your issue:
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.GET("/base/file1", func(c *gin.Context) {
c.HTML(http.StatusOK, "base/file1.tmpl", gin.H{
"title": "base",
})
})
router.GET("/other/file2", func(c *gin.Context) {
c.HTML(http.StatusOK, "file2.tmpl", gin.H{
"title": "other",
})
})
router.GET("/other/file2-1", func(c *gin.Context) {
c.HTML(http.StatusOK, "other/file2.tmpl", gin.H{
"title": "other",
})
})
router.Run(":8080")
}
The templates dir :
templates
├── base
│ └── file1.tmpl
├── other
│ └── file2.tmpl
├── posts
│ └── index.tmpl
└── users
└── index.tmpl
file1:
{{ define "base/file1.tmpl" }}
<html><h1>
{{ .title }}
</h1>
</html>
{{ end }}
file2
<html><h1>
{{ .title }}
</h1>
</html>
Test cases:
$ curl http://localhost:8080/base/file1
<html><h1>
base
</h1>
</html>
$ curl http://localhost:8080/other/file2-1
# GIN Log: Error #01: html/template: "other/file2.tmpl" is undefined
$ curl http://localhost:8080/other/file2
<html><h1>
other
</h1>
</html>
If you forgot to define your template file in the {{define}}
, I think add it will solve your issue.
@dreamjz you are correct, the templates are not wrapped {{define
Thank you for tracking this down. The documentation should be updated to state this, dont you think?