【Golang】ExecuteTemplate関数で渡した値を、scriptタグ内で参照する方法

経緯

Goのhtml/templateパッケージのExecuteTemplate関数の第二引数に何らかの値を代入することで、描画するhtmlに値を渡すことができ、htmlのタグ内に展開する例がよく紹介されています。しかし、渡した値が配列やスライスの場合、scriptタグ内で参照する時と、scriptタグ外で参照する時で記法が少し異なってきます。

scriptタグ内とscriptタグ外で参照方法が同じ場合

以下の2つの例のように1つのデータを渡す時は、scriptタグ内とscriptタグ外で参照方法は変わりません。

なお、scriptタグ内で{{.}}を使うとIDEの設定によってはエラー判定となりますが、問題なく動作します。

①単純な値を渡す場合

   hoge := "hoge"

    tpl := template.Must(template.ParseFiles("./templates/test.html"))

    tpl.ExecuteTemplate(w, "test.html", hoge)
<body>
  <p>{{.}}</p>  //hoge
</body>
<script>
  console.log({{.}})  //hoge
</script>

②構造体を1つ渡す場合

type Person struct {
    //json変換用のキー名の設定はなくてもok
    Name   string `json:"name"`
    Age    int    `json:"age"`
    Height int    `json:"height"`
}

    NewPerson := new(Person)
    NewPerson.Name = "John"
    NewPerson.Age = 30
    NewPerson.Height = 180

    tpl := template.Must(template.ParseFiles("./templates/test.html"))

    tpl.ExecuteTemplate(w, "test.html", NewPerson)
}
<body>
  <p>{{.}}</p>  //{John 30 180}
  <p>{{.Name}}</p>  //John
  <p>{{.Age}}</p>  //30
  <p>{{.Height}}</p>  //180
</body>
<script>
  console.log({{.}})  //{name: "John", age: 30, height: 180}

  //json用のキー名を設定している場合も、元の構造体のフィールド名を使う!
  console.log({{.Name}})  //John
  console.log({{.Age}})  //30
  console.log({{.Height}})  //180
</script>

scriptタグ内とscriptタグ外で参照方法が異なる場合

しかし、配列やスライスといったデータを渡す場合、参照方法が異なってきます。scriptタグ外では{{index . 0}}{{range .}} {{end}}などで参照を行いますが、scriptタグ内では{{.}}[0]{{.}}[1]というように{{.}}[n]で配列の要素を取得する形でまず参照を行います。配列の要素が構造体の場合、{{.}}[0].nameというようにキー名を指定し、値を取得することができます。

type Person struct {
    //json変換用のキー名の設定はなくてもok
    Name   string `json:"name"`
    Age    int    `json:"age"`
    Height int    `json:"height"`
}

func testHandler(w http.ResponseWriter, r *http.Request) {

    NewPerson1 := new(Person)
    NewPerson1.Name = "John"
    NewPerson1.Age = 30
    NewPerson1.Height = 180

    NewPerson2 := new(Person)
    NewPerson2.Name = "Mike"
    NewPerson2.Age = 25
    NewPerson2.Height = 175

    Slice := []*Person{NewPerson1, NewPerson2}

    tpl := template.Must(template.ParseFiles("./templates/test.html"))

    tpl.ExecuteTemplate(w, "test.html", Slice)
<body>
  <p>{{.}}</p>  //[0xc000169240 0xc000169260]などと表示される。
  <p>{{index . 0}}</p>  //{John 30 180}
  <p>{{(index . 0).Name}}</p>  //John
</body>
<script>
    console.log({{.}})  //↓(2) [{…}, {…}]
                         //→0: {Name: "John", Age: 30, Height: 180}
                         //→1: {Name: "Mike", Age: 25, Height: 175}
                         //→length: 2
                         //→__proto__: Array(0)
  console.log({{.}}[0]) //{Name: "Mike", Age: 25, Height: 175}

  console.log({{.}}[1]["name"]) //Mike  ※hashの値を取得する形式でも可
  console.log({{.}}[1].name) //Mike
  console.log({{.}}[1].age)  //25
  console.log({{.}}[1].height)  //175
</script>

ちなみに、例では構造体の定義でjson変換時のキー名の設定を追加していますが、設定しなくても値の取得が行えます。その場合はそのままフィールド名をキー名に使用して個々の値を取得できます。

ExecuteTemplate関数で渡される値について

html/templateパッケージの仕様書には詳しい記載はないのですが、これまでの例を見た限り、ExecuteTemplate関数での値渡しは以下の規則で行われるようです。
①ただの変数・配列などの単純な部分はそのまま渡す。
②構造体・連想配列などの部分があれば、json形式に変換する。 (json変換時のキー名が設定されていなければ、フィールド名をそのまま使用する)

注意点

値の参照でエラーが起きると、scriptタグ内の関数が全て実行されなくなります。