3
votes

I require basic incrementation arithmetic and loop for my project to keep the template readable and populate a 9x9 grid with values. The values are stored in a string array and so it is necessary to be able to have control over the index.

Here is my handler with both template functions defined:

func HomeHandler(w http.ResponseWriter, req *http.Request) {
    t := template.New("home.html").Funcs(template.FuncMap{
        "loop": func(n int) []struct{} {
            return make([]struct{}, n)
        },
    }).Funcs(template.FuncMap{
        "inc": func(n int) int {
            return n + 1
        },
    })

    t, err := t.ParseFiles("templates/home.html")

    if err != nil {
        log.Print("template/home error:", err)
    }
    t.ExecuteTemplate(w, "home.html", nil)
}

To create the grid I use the loop function like so:

{{ range loop 3}}
<tbody>
    {{ range loop 3}}
    <tr>
        {{ range loop 9}} 
        <td> <input value="1" type="text" name="value[]" maxlength="1" size="1">
        {{end}}
    {{end}}
{{end}}

However, I'd like to set the value attribute of the input element to the correct value with my data. I believe that I can access the index with the following:

{{index .MyArray 3}}

I will replace "3" with a counter that I'll need to be able to increment correctly.

Unfortunately, it seems like I can't correctly reassign the variable as I can only increment it from 0 to 1 at most.

Here is my template with my counter:

{{$count := 0}}
{{ range loop 3}}
<tbody>
    {{ range loop 3}}
    <tr>
        {{ range loop 9}} 
        {{$count := inc $count}}
        <td> <input value="1" type="text" name="value[]" maxlength="1" size="1">
        {{end}}
    {{end}}
{{end}}
1

1 Answers

6
votes

How about doing it the other way around, since ranging over the actual data is something that templates do easily? You can do without loop and inc and start with

{{ range $index, $value := .MyArray }}
<td><input value="{{ $value }}" type="text" name="value[]" maxlength="1" size="1">
{{ end }}

which will get you all of the inputs you need, but without the surrounding markup, so how do we get that? A little bit of modular arithmetic. Define a template function like so:

"each": func(interval, n int) bool {
    return n % interval == 0
}

then we can pad things out:

{{ range $index, $value := .MyArray }}
{{ if each 27 $index }}<tbody>{{ end }}
{{ if each 9 $index }}<tr>{{ end }}
<td><input value="{{ $value }}" type="text" name="value[]" maxlength="1" size="1">
{{ end }}