ダッシュで奪取

ゲーム、読書、人生

【Go/Echo】html/templateで共通レイアウトを指定したい

環境

  • Go 1.20.7
  • Echo 4.11.1

やりたいこと

  • http/templateを使う
  • layout.htmlの中で、各パスに対応したHTMLを表示したい
  • 雑に言うと、Railsのpartialみたいなことをしたい

やったこと

  • 全体的な内容はこちら

github.com

テンプレートを登録する部分

  • views/_layout.html という名前で共通レイアウトを作っている
  • 各種Viewは views/*/*.html にある
  • 実際のファイル:kyoruni/echo-crud/route/router.go
e := echo.New()

// テンプレートを登録
t := template.Must(template.New("base").Funcs(sprig.FuncMap()).ParseGlob("views/*.html"))
t.ParseGlob("views/*/*.html")
e.Renderer = &utils.Template{
    Templates: t,
}

e.GET("/", controller.GetPokemons)
e.GET("/pokemons", controller.GetPokemons)
e.GET("/types", controller.GetTypes)
return e

テンプレートを返す部分

type Template struct {
    Templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return template.Must(template.Must(t.Templates.Lookup("layout").Clone()).AddParseTree("content", t.Templates.Lookup(name).Tree)).ExecuteTemplate(w, "layout", data)
}

共通レイアウト

  • {{- template "content" }} 部分に、各パスに対応したViewの内容が入る
  • 実際のファイル:kyoruni/echo-crud/views/
{{- define "layout" }}
{{- $param := . }}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{- $param.pageTitle }}</title>
</head>
<body>
  <div class="container">
    {{- template "content" }}
  </div>
</body>
</html>
{{ end -}}

呼び出し元

func GetPokemons(c echo.Context) error {
    return c.Render(http.StatusOK, "pokemons/index", map[string]interface{}{
        "pageTitle": "ポケモン一覧",
    })
}

func GetTypes(c echo.Context) error {
    return c.Render(http.StatusOK, "types/index", map[string]interface{}{
        "pageTitle": "タイプ一覧",
    })
}

テンプレート

{{- define "pokemons/index" }}
<h2>pokemons index!!</h2>
{{- end }}
{{- define "types/index" }}
<h2>types index!!</h2>
{{- end }}

参考URL