Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I run a range within a range in golang using html/template

I want to run a range within a range using html/template. The sample code (https://go.dev/play/p/fxx61RwIDhd) looks like this:

package main

import (
    "html/template"
    "os"
)

type Runtest struct {
    ID          int
    SessionType string
}

type Setting struct {
    ID   int
    Type string
}

type templateData struct {
    Runtest []*Runtest
    Setting []*Setting
}

func main() {
    tmpl := template.Must(template.New("nested-range").Parse(`
        {{ range .Runtest }}
            <h1>Runtest ID: {{ .ID }}, Session Type: {{ .SessionType }}</h1>
            <ul>
                {{ range .Setting }}
                    <li>Setting ID: {{ .ID }}, Type: {{ .Type }}</li>
                {{ end }}
            </ul>
        {{ end }}
    `))

    runtestsList := []*Runtest{
        {ID: 1, SessionType: "Type A"},
        {ID: 2, SessionType: "Type B"},
    }

    settingsList := []*Setting{
        {ID: 101, Type: "Setting 1"},
        {ID: 102, Type: "Setting 2"},
        {ID: 201, Type: "Setting X"},
        {ID: 202, Type: "Setting Y"},
    }

    data := templateData{
        Runtest: runtestsList,
        Setting: settingsList,
    }

    err := tmpl.Execute(os.Stdout, data)
    if err != nil {
        panic(err)
    }
}

I get the following error when executing the code:

panic: template: nested-range:5:13: executing "nested-range" at <.Setting>: can't evaluate field Setting in type *main.Runtest

It seems like the template engine sees {{ range .Setting }} as part of {{ range .Runtest }}.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If you try it with just one range the code will work: https://go.dev/play/p/CUOxnBfvAo1

Also one range after the other: https://go.dev/play/p/mge2JsQYOYD

Is it possible to run a range within range using data that is not part of the first range data?

>Solution :

It is a scoping problem. range starts a new scope with the iteration variable being .. That is, when you have

{{range .Runtest}}
  // Here . points to the current element of the Runtest

You can still refer to the variables in the global scope using $ prefix:

 {{ range .Runtest }}
            <h1>Runtest ID: {{ .ID }}, Session Type: {{ .SessionType }}</h1>
            <ul>
                {{ range $.Setting }}

Alternatively, you can define loop variables yourself. This is especially useful if you have multiple levels of range and you need to access variables defined in one of the enclosing ones:

{{ range $key1, $value1 := .someList }}
   {{ range $key2, $value2 := $value1.otherList }}
      // Here, you can access both $value1 and $value2, 
      // as well as the global scope $.GlobalScopeVar
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading