Introduction Gin HTML template and how integration with bootstrap
Gin is going web framework which include server-side render template, we can transfer variable into a template and render by double braces {{ … }}.
In this article, We will introduce how to use gin template, finally will include how to integrate bootstrap with gin HTML template.
Getting start
First, we need to prepare a gin framework and. Fellowing content you also can reference with gin official Github tutorial.
Notice: I have change the loadHTMLGlob rule from * to *.tmpl
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*.tmpl")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
router.Run(":8080")
}
Create a templates folder and index.tmpl file
<html>
<h1>
{{ .title }}
</h1>
</html>
How to transfer data into template
In fellowing will showing how to transfer data into the template.
1. The single variable of non-struct types
When transfer value of non-struct types,
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"FielName": "Main website",
})
We can just use {{.FielName}}
action
2. Range loop data
When transferring a slice, can using the range
action for loop data in gin.
data := fetchUsers()
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"Users": data,
})
func fetchUsers() []string {
data := []string{"Adam", "Brown", "Cayla"}
return data
}
template:
{{ range .Users }}
{{ . }}
{{ end }}
3. Render loop data for slice data with struct
type Users struct {
Name string
Phone string
Age int
}
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*.tmpl")
userData := []Users{
{Name: "Adam", Phone: "099911111", Age: 23},
{Name: "Brown", Phone: "0933222222", Age: 22},
{Name: "Cayla", Phone: "0933333333", Age: 18},
}
r.GET("/", func(c *gin.Context) {
"userdata": userData,
}
In templates, demo with range
, when
, range key value
, all of three actions get same result:
{{ range .userdata }}
Name: {{ .Name }},
Phone: {{ .Phone }},
Age: {{ .Age }}
{{ end }}
{{ when .userdata }}
Name: {{ .Name }},
Phone: {{ .Phone }},
Age: {{ .Age }}
{{ end }}
{{ range $key, $value := .userdata }}
{{ $key }}
Name: {{ $value.Name }},
Phone: {{ $value.Phone }},
Age: {{ $value.Age }}
{{ end }}
When we using with
, you also can define a variable with {{ with $x := <^>result-of-some-action<^> }}
Intergration with Bootstrap statics file
Download Bootstrap (here is using v5.0.1) to local, create an assets folder, and put the bootstrap file in assets.
Add assets static route in gin:
r.Static("/assets", "./assets")
Now you can access the bootstrap file in the assets path.
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="/assets/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous" >
<title>{{ .title }}</title>
</head>
<body>
<h1>{{ .title }}</h1>
<script src="/assets/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script>
</body>
Create a reusable template in Gin
Using sub-template can separate re-usable component like header, footner, navigator…
First, create folder and file like fellowing:
|-templates
|-globals
|-header.tmpl
|-footer.tmpl
|-static
|-(static files)
|-users
|-users.tmpl
|-home
|-index.tmpl
templates/globals/header.tmpl
{{ define "globals/header.tmpl" }}
<header>
<h1>{{ .title }}</h1>
<a href="/">Home</a>
<a href="/users/">User</a>
</header>
{{ end }}
templates/globals/footer.tmpl
{{ define "globals/footer.tmpl" }}
<footer>
<p>
copyright by test {{ .title }}
</p>
</footer>
{{ end }}
templates/users/users.tmpl
{{ define "users/users.tmpl" }}
{{ template "globals/header.tmpl" .}}
<p>
user index file
{{ .title }}
</p>
{{ template "globals/footer.tmpl" .}}
{{ end }}
templates/home/index.tmpl
<body>
{{ template "globals/header.tmpl" .}}
<div>
CONETNETN AREA
</div>
{{ template "globals/footer.tmpl" .}}
main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
//ping
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
//load html file
r.LoadHTMLGlob("templates/**/*.tmpl")
//static path
r.Static("/assets", "./assets")
//show home
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "home/index.tmpl", gin.H{
"title": "Home Page",
})
})
//show user template
r.GET("/users", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/users.tmpl", gin.H{
"title": "Users Page",
})
})
//run
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
Others
Fellowing are some issue notes:
golang “gin” is an unexported field of struct type
This error happened when unexported field is used.
type Users struct {
id int
key string
}
Use capitals for exported fields in a struct, for referring in the outside package.
type Users struct {
Id int
Key string
}