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



# はじめに

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

具体的には

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

などの値です。

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



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

# 環境
- macOS Catalina 10.15  
- go 1.12.9

# 0.何も渡さず実行

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

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

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



```go: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)
	}
}
```

```html: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`で実行した結果がこちらです。

```terminal:実行結果
$ 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引数に変数を指定することで渡せます。

```go: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です。  
値を受け取るには`{{.}}`の表記が必要になります。  
独特の表記ですが基本となるので慣れてください。

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

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

</body>
</html>
```

実行結果がこちらです。

```terminal:実行結果
$ 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>⏎
```

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

### 複数回値を受け取れる

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

```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>
```

```terminal:実行結果
$ 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から受け取った値を構造体に入れて、それを表示するといった感じでしょう。

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

```go: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)
	}
}
```

今回は`Name`と`Age`の2つのフィールドを持った構造体を用意しました。  
ベタですね。

htmlはこちらです。

```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}}`のようにドットに続けてフィールド名を書きます。  

一方で、`{{.}}`のみだと構造体がそのまま表示されます。  
これは感覚そのままですね。

では実行結果です。

```terminal:実行結果
$ 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`として構造体を複数使用したい場合があるでしょう。

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

```go: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 .}}`を使用します。  
実際にコードを見るのが速いでしょう。  

```html: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}}`を忘れないようにしてください。

では実行結果です。

```terminal:実行結果
$ 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`を使用します。  
これもコードを見たほうが速いでしょう。

```html: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}}`のように`()`でくくる必要があります。

それでは実行結果です。

```terminal:実行結果
$ 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ページ](https://golang.org/pkg/text/template/)のFunctionの部分を参照してください。  
ページがtext/templateとなっていますが、同じように使えます。(html/templateのページで詳細が見当たらなかった)


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

templateでは構造体のメソッドを実行することも可能です。  
ただしメソッドの実装は値渡しでないといけません。（ポインタ渡しはエラー）  

```go: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)
	}
}

```


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

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

</body>
</html>
```

実行結果です。

```terminal:実行結果
$ 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内でパイプ`|`を使用する方法など、他にも様々な手法があります。  
反響があれば記事を書こうと思います。

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