27
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

GolangでHTMLのtemplateに値を渡す方法

はじめに

Goではhttp/templateを使用してhtmlのテンプレートに値を渡すことができます。

具体的には

  • 変数
  • スライス
  • マップ
  • 構造体

などの値です。

今回は、基本となる変数と、使用機会が一番多いであろう構造体について説明していきます。

Web開発に使用する技術ですが、検索しても情報があまり出てこなかったので書きました。

環境

  • macOS Catalina 10.15
  • go 1.12.9

0.何も渡さず実行

メインのGoとhtmlファイルです。

これらを基本に説明していきます。

ディレクトリ構造
.
├── main.go
└── tpls.html
main.go
package main

import (
    "html/template"
    "log"
    "os"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseFiles("tpls.html"))
}

func main() {
    err := tpl.Execute(os.Stdout, nil) // dataは渡さない
    if err != nil {
        log.Fatalln(err)
    }
}
tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>hoge</h1>

</body>
</html>

main.go を go run main.goで実行した結果がこちらです。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>hoge</h1>

</body>
</html>

なんの変哲もありませんね。

今回はターミナルに標準出力しているので全文表示されますが、実際にはwebブラウザに読み込ませるので、hoge だけが表示されるはずです。

ではテンプレートの使い方を見ていきましょう。

1.変数の値を渡す

まずは変数を渡します。

tpl.Executeの第2引数に変数を指定することで渡せます。

main.go
package main

import (
    "html/template"
    "log"
    "os"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseFiles("tpls.html"))
}

func main() {

    var Age = 235

    err := tpl.Execute(os.Stdout, Age) // 変数を指定
    if err != nil {
        log.Fatalln(err)
    }
}

次にhtmlです。

値を受け取るには{{.}}の表記が必要になります。

独特の表記ですが基本となるので慣れてください。

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>{{.}}</h1>  <!-- 値を受け取る -->

</body>
</html>

実行結果がこちらです。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>235</h1>

</body>
</html>

値が渡されているのがわかります。

複数回値を受け取れる

なお、受け取った値は複数回表示したり、変数に代入することができます。

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>{{.}}</h1>  <!-- 同じ値を複数回受け取る事もできる -->
<h1>{{.}}</h1>

<h1>{{$Age := .}}</h1>  <!-- 代入したときは表示されない -->
<h1>{{$Age}}</h1>  <!-- 値を表示 -->

</body>
</html>
実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>235</h1>
<h1>235</h1>

<h1></h1>
<h1>235</h1>

</body>
</html>

2.構造体の値を渡す

次に構造体の値を渡します。

実際の開発では構造体を使うことが一番多いでしょう。

具体的にはjsonから受け取った値を構造体に入れて、それを表示するといった感じでしょう。

では、実行して行きます。

main.go
package main

import (
    "html/template"
    "log"
    "os"
)

type Person struct {
    Name string
    Age  int
}

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseFiles("tpls.html"))
}

func main() {
    p1 := Person{
        Name: "hogefuga",
        Age:  28,
    }

    err := tpl.Execute(os.Stdout, p1)
    if err != nil {
        log.Fatalln(err)
    }
}

今回はNameAgeの2つのフィールドを持った構造体を用意しました。

ベタですね。

htmlはこちらです。

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>{{.}}</h1>
<h2>{{.Name}}</h2>  <!-- フィールドにアクセスする -->
<h2>{{.Age}}</h2>

</body>
</html>

フィールドにアクセスするには{{.Name}}のようにドットに続けてフィールド名を書きます。

一方で、{{.}}のみだと構造体がそのまま表示されます。

これは感覚そのままですね。

では実行結果です。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<h1>{hogefuga 28}</h1>
<h2>hogefuga</h2>
<h2>28</h2>

</body>
</html>

全く説明した通りの結果です。

3.構造体のスライスを渡す

実際の開発では、[]hogestructとして構造体を複数使用したい場合があるでしょう。

こちらのケースも見ていきます。

main.go
package main

import (
    "html/template"
    "log"
    "os"
)

type Person struct {
    Name string
    Age  int
}


var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseFiles("tpls.html"))
}

func main() {
    p1 := Person{
        Name: "hogefuga",
        Age:  28,
    }
    p2 := Person{
        Name: "hogeeeeeee",
        Age:  51,
    }
    p3 := Person{
        Name: "fugagagaga",
        Age:  3,
    }

    var persons = []Person{p1, p2, p3}

    err := tpl.Execute(os.Stdout, persons)
    if err != nil {
        log.Fatalln(err)
    }
}

やっているのは構造体のスライスを渡しているだけです。

次にhtmlです。

スライスの全要素を順に表示するには{{range .}}を使用します。

実際にコードを見るのが速いでしょう。

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<ul>
    {{range .}}
        <li>{{.Name}} - {{.Age}}</li>
    {{end}}
</ul>

</body>
</html>

rangeを使用するときは{{end}}を忘れないようにしてください。

では実行結果です。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<ul>

        <li>hogefuga - 28</li>

        <li>hogeeeeeee - 51</li>

        <li>fugagagaga - 3</li>

</ul>

</body>
</html>

正しく表示されたと思います。

スライス要素に個別にアクセス

ちなみにスライスの要素に個別にアクセスしたいときは、html内でデフォルト関数のindexを使用します。

これもコードを見たほうが速いでしょう。

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<ul>
    {{index . 1}}  <!-- スライスの要素に個別にアクセス -->
    {{index . 2}}
    {{(index . 0).Name}}  <!-- 要素のフィールドにアクセスすることも可能-->
</ul>

</body>
</html>

個別要素のフィールドにアクセスするには{{(index . 0).Name}}のように()でくくる必要があります。

それでは実行結果です。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

<ul>
    {hogeeeeeee 51}
    {fugagagaga 3}
    hogefuga
</ul>

</body>
</html>

デフォルト関数はindexの他にも多数存在します。

詳細はgolangのtemplateページのFunctionの部分を参照してください。

ページがtext/templateとなっていますが、同じように使えます。(html/templateのページで詳細が見当たらなかった)

4.構造体のメソッドについて

templateでは構造体のメソッドを実行することも可能です。

ただしメソッドの実装は値渡しでないといけません。(ポインタ渡しはエラー)

main.go
package main

import (
    "html/template"
    "log"
    "os"
)

type Person struct {
    Name string
    Age  int
}

// func (p *Person) のようなポインタ渡しはエラーが出る
func (p Person) DoubleAge() int {
    return p.Age * 2
}

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseFiles("tpls.html"))
}

func main() {
    p1 := Person{
        Name: "hogefuga",
        Age:  28,
    }

    err := tpl.Execute(os.Stdout, p1)
    if err != nil {
        log.Fatalln(err)
    }
}

tpls.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>

{{.DoubleAge}}  <!-- methodも書き方は同じ -->

</body>
</html>

実行結果です。

実行結果
$ go run main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Golang Template Test</title>
</head>
<body>


<ul>
    56
</ul>

</body>
</html>

Ageを2倍した値が表示されます。

おわりに

今回の記事は以上になります。

基本的な開発はこの記事の内容で十分行えると思います。

html/templateには関数を渡すfuncmapや、template内でパイプ|を使用する方法など、他にも様々な手法があります。

反響があれば記事を書こうと思います。

最後まで読んでいただきありがとうございました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
27
Help us understand the problem. What are the problem?