Search code examples
gogo-gin

Golang Gin Base HTML Template


I have a base html template and want to work it with in all html files.

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // Şablon dosyalarını yükleme
    r.LoadHTMLGlob("templates/*.html")

    r.GET("/page1", func(c *gin.Context) {
        c.HTML(200, "base.html", gin.H{
            "title":   "Page 1 IS HERE",
            "content": "page1.html",
        })
    })

    r.GET("/page2", func(c *gin.Context) {
        c.HTML(200, "base.html", gin.H{
            "title":   "Page 2 IS HERE",
            "content": "page2.html",
        })
    })

    r.Run("127.0.0.1:8080")
}

my base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{.title}}</title>
</head>
<body>
    <h1>BASELINE</h1>
    <div id="content">
        {{template "content" .}}
    </div>
</body>
</html>

page1.html

{{define "content"}}
<h2>Welcome to Page 1</h2>
<p>This is the content of Page 1.</p>
{{end}}

page2.html

{{define "content"}}
<h2>Welcome to Page 2</h2>
<p>This is the content of Page 2.</p>
{{end}}

Print; /page1 = Welcome to Page 2 This is the content of Page 2.

/page2 = Welcome to Page 2 This is the content of Page 2.

When I run this code, both link use page2.html content. How can I fix it?


Solution

  • I was able to achieve what you need by using the HTML templates in the following way. First, let me present my project structure:

    • appName
      • templates
        • footer.tmpl
        • header.tmpl
        • page1.tmpl
        • page2.tmpl
      • main.go

    Now, let's start with templates definition.

    Templates definition

    header.tmpl file

    {{define "header.tmpl" }}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{.title}}</title>
    </head>
    <body>
        <h1>BASELINE</h1>
        <div id="content">
    {{end}}
    

    footer.tmpl file

    {{define "footer.tmpl"}}
    </div>
    </body>
    </html>
    {{end}}
    

    page1.tmpl file

    {{template "header.tmpl"}}
    <h2>Welcome to Page 1</h2>
    <p>This is the content of Page 1.</p>
    {{template "footer.tmpl"}}
    

    page2.tmpl file

    {{template "header.tmpl"}}
    <h2>Welcome to Page 2</h2>
    <p>This is the content of Page 2.</p>
    {{template "footer.tmpl"}}
    

    The main.go file

    package main
    
    import (
        "github.com/gin-gonic/gin"
    )
    
    func main() {
        gin.SetMode(gin.DebugMode)
        r := gin.Default()
    
        // load templates
        r.LoadHTMLGlob("templates/*.tmpl")
    
        r.GET("/page1", func(c *gin.Context) {
            c.HTML(200, "page1.tmpl", gin.H{
                "title": "Page 1 IS HERE",
            })
        })
    
        r.GET("/page2", func(c *gin.Context) {
            c.HTML(200, "page2.tmpl", gin.H{
                "title": "Page 2 IS HERE",
            })
        })
    
        r.Run("127.0.0.1:8080")
    }
    

    First, we added the invocation to gin.SetMode(gin.DebugMode). Thanks to this, we're able to see which templates are actually loaded in our gin.Renderer instance.
    By using the method LoadHTMLGlob we load all of them. The pattern matches any *.tmpl file we define on the file system.
    The remaining code is more or less the same as you wrote within the question.
    By using this method you should be able to avoid the duplication of the common structure by using two tmpl files.
    Probably, there is an even more elegant way of achieving this. In case someone finds it, just let me know, thanks!