Templates

Go menyediakan package text/template dan html/template untuk menghasilkan output terformat. Package html/template khususnya aman untuk konten HTML.

Contoh Masalah

Bagaimana cara:

  1. Membuat dan menggunakan template
  2. Menggunakan fungsi template
  3. Nested templates
  4. Safe HTML output

Penyelesaian

package main

import (
    "fmt"
    "html/template"
    "os"
    "strings"
    "time"
)

// 1. Data structures
type User struct {
    Name      string
    Age       int
    Email     string
    CreatedAt time.Time
}

type Post struct {
    Title    string
    Content  string
    Author   User
    Tags     []string
    Comments []Comment
}

type Comment struct {
    Author  string
    Content string
    Date    time.Time
}

// 2. Custom template functions
var funcMap = template.FuncMap{
    "upper": strings.ToUpper,
    "formatDate": func(t time.Time) string {
        return t.Format("02 Jan 2006")
    },
    "inc": func(n int) int {
        return n + 1
    },
    "join": strings.Join,
}

// Template files
const (
    baseTemplate = `
<!DOCTYPE html>
<html>
<head>
    <title>{{template "title" .}}</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .post { margin-bottom: 20px; }
        .comments { margin-left: 20px; }
    </style>
</head>
<body>
    {{template "content" .}}
    {{template "footer" .}}
</body>
</html>
`

    postTemplate = `
{{define "title"}}{{.Title}}{{end}}

{{define "content"}}
<div class="post">
    <h1>{{.Title}}</h1>
    <p>{{.Content}}</p>
    
    <h3>Author</h3>
    {{template "user" .Author}}
    
    <h3>Tags</h3>
    <p>{{join .Tags ", " | upper}}</p>
    
    <h3>Comments</h3>
    <div class="comments">
        {{range $i, $comment := .Comments}}
            {{template "comment" $comment}}
        {{else}}
            <p>No comments yet.</p>
        {{end}}
    </div>
</div>
{{end}}

{{define "footer"}}
<footer>
    <p>&copy; {{.Author.Name}} - {{formatDate .Author.CreatedAt}}</p>
</footer>
{{end}}
`

    userTemplate = `
{{define "user"}}
<div class="user">
    <p>Name: {{.Name}}</p>
    <p>Age: {{.Age}}</p>
    <p>Email: {{.Email}}</p>
    <p>Member since: {{formatDate .CreatedAt}}</p>
</div>
{{end}}
`

    commentTemplate = `
{{define "comment"}}
<div class="comment">
    <p><strong>{{.Author}}</strong> - {{formatDate .Date}}</p>
    <p>{{.Content}}</p>
</div>
{{end}}
`
)

func main() {
    // Create template
    tmpl := template.New("base").Funcs(funcMap)
    
    // Parse all templates
    template.Must(tmpl.Parse(baseTemplate))
    template.Must(tmpl.Parse(postTemplate))
    template.Must(tmpl.Parse(userTemplate))
    template.Must(tmpl.Parse(commentTemplate))

    // Sample data
    post := Post{
        Title:   "Belajar Go Templates",
        Content: "Go menyediakan sistem template yang powerful...",
        Author: User{
            Name:      "John Doe",
            Age:       30,
            Email:     "john@example.com",
            CreatedAt: time.Now().Add(-24 * time.Hour * 365),
        },
        Tags: []string{"go", "programming", "template"},
        Comments: []Comment{
            {
                Author:  "Alice",
                Content: "Artikel yang sangat membantu!",
                Date:    time.Now().Add(-24 * time.Hour),
            },
            {
                Author:  "Bob",
                Content: "Saya suka penjelasannya.",
                Date:    time.Now().Add(-12 * time.Hour),
            },
        },
    }

    // Execute template
    err := tmpl.Execute(os.Stdout, post)
    if err != nil {
        fmt.Printf("Error executing template: %v\n", err)
    }
}

File Template

Simpan template dalam file terpisah:

templates/base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{{template "title" .}}</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .post { margin-bottom: 20px; }
        .comments { margin-left: 20px; }
    </style>
</head>
<body>
    {{template "content" .}}
    {{template "footer" .}}
</body>
</html>

templates/post.html:

{{define "title"}}{{.Title}}{{end}}

{{define "content"}}
<div class="post">
    <h1>{{.Title}}</h1>
    <p>{{.Content}}</p>
    
    <h3>Author</h3>
    {{template "user" .Author}}
    
    <h3>Tags</h3>
    <p>{{join .Tags ", " | upper}}</p>
    
    <h3>Comments</h3>
    <div class="comments">
        {{range $i, $comment := .Comments}}
            {{template "comment" $comment}}
        {{else}}
            <p>No comments yet.</p>
        {{end}}
    </div>
</div>
{{end}}

{{define "footer"}}
<footer>
    <p>&copy; {{.Author.Name}} - {{formatDate .Author.CreatedAt}}</p>
</footer>
{{end}}

Cara menggunakan file template:

// Load templates from files
tmpl := template.New("base").Funcs(funcMap)
template.Must(tmpl.ParseFiles(
    "templates/base.html",
    "templates/post.html",
    "templates/user.html",
    "templates/comment.html",
))

Penjelasan Kode

  1. Basic Template

    • Variable substitution
    • Control structures
    • Nested templates
  2. Template Functions

    • Built-in functions
    • Custom functions
    • Pipelines
  3. Security

    • HTML escaping
    • Safe content
    • XSS prevention

Output

<!DOCTYPE html>
<html>
<head>
    <title>Belajar Go Templates</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .post { margin-bottom: 20px; }
        .comments { margin-left: 20px; }
    </style>
</head>
<body>
    <div class="post">
        <h1>Belajar Go Templates</h1>
        <p>Go menyediakan sistem template yang powerful...</p>
        
        <h3>Author</h3>
        <div class="user">
            <p>Name: John Doe</p>
            <p>Age: 30</p>
            <p>Email: john@example.com</p>
            <p>Member since: 21 Jan 2023</p>
        </div>
        
        <h3>Tags</h3>
        <p>GO, PROGRAMMING, TEMPLATE</p>
        
        <h3>Comments</h3>
        <div class="comments">
            <div class="comment">
                <p><strong>Alice</strong> - 20 Jan 2024</p>
                <p>Artikel yang sangat membantu!</p>
            </div>
            <div class="comment">
                <p><strong>Bob</strong> - 20 Jan 2024</p>
                <p>Saya suka penjelasannya.</p>
            </div>
        </div>
    </div>
    <footer>
        <p>&copy; John Doe - 21 Jan 2023</p>
    </footer>
</body>
</html>

Tips

  • Gunakan html/template untuk web
  • Pisahkan template dalam file
  • Manfaatkan template functions
  • Handle error dengan baik
  • Perhatikan keamanan output