Iterating through map in template
Asked Answered
K

2

130

I am trying to display a list gym classes (Yoga, Pilates etc). For each class type there are several classes, so I want to group all the Yoga classes, and all the Pilates classes and so on.

I made this function to take a slice and make a map of it

func groupClasses(classes []entities.Class) map[string][]entities.Class {
    classMap := make(map[string][]entities.Class)
    for _, class := range classes {
        classMap[class.ClassType.Name] = append(classMap[class.ClassType.Name], class)
    }
    return classMap
}

The problem is now how can I iterate through it, according to http://golang.org/pkg/text/template/, you need to access it in .Key format, I don't know the keys (unless I also passed a slice of keys into the template). How do I unpack this map in my view.

All I have currently is

{{ . }} 

which displays something like:

map[Pilates:[{102 PILATES ~/mobifit/video/ocen.mpg 169 40 2014-05-03 23:12:12 +0000 UTC 2014-05-03 23:12:12 +0000 UTC 1899-12-30 00:00:00 +0000 UTC {PILATES Pilates 1 2014-01-22 21:46:16 +0000 UTC} {1 [email protected] password SUPERADMIN Lee Brooks {Male true} {1990-07-11 00:00:00 +0000 UTC true} {1.85 true} {88 true} 2014-01-22 21:46:16 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false} {0001-01-01 00:00:00 +0000 UTC false} {0001-01-01 00:00:00 +0000 UTC false}} [{1 Mat 2014-01-22 21:46:16 +0000 UTC}]} {70 PILATES ~/mobifit/video/ocen.mpg 119 66 2014-03-31 15:12:12 +0000 UTC 2014-03-31 15:12:12 +0000 UTC 1899-12-30 00:00:00 +0000 UTC 
Knowlton answered 23/1, 2014 at 8:1 Comment(0)
D
232

Check the Variables section in the Go template docs. A range may declare two variables, separated by a comma. The following should work:

{{ range $key, $value := . }}
   <li><strong>{{ $key }}</strong>: {{ $value }}</li>
{{ end }}
Dried answered 23/1, 2014 at 8:22 Comment(0)
O
52

As Herman pointed out, you can get the index and element from each iteration.

{{range $index, $element := .}}{{$index}}
{{range $element}}{{.Value}}
{{end}}
{{end}}

Working example:

package main

import (
    "html/template"
    "os"
)

type EntetiesClass struct {
    Name string
    Value int32
}

// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var htmlTemplate = `{{range $index, $element := .}}{{$index}}
{{range $element}}{{.Value}}
{{end}}
{{end}}`

func main() {
    data := map[string][]EntetiesClass{
        "Yoga": {{"Yoga", 15}, {"Yoga", 51}},
        "Pilates": {{"Pilates", 3}, {"Pilates", 6}, {"Pilates", 9}},
    }

    t := template.New("t")
    t, err := t.Parse(htmlTemplate)
    if err != nil {
        panic(err)
    }

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

}

Output:

Pilates
3
6
9

Yoga
15
51

Playground: http://play.golang.org/p/4ISxcFKG7v

Orford answered 23/1, 2014 at 8:33 Comment(4)
Hey @ANisus, I have a requirement of generating json through a template like below but it has also extra commas like in addresses array in given example Output ``` {"name": "Mus", "adresses": [{"address": "A"},{"address": "B"},]} ``` Example code's link play.golang.org/p/nD08y0noPHvChampignon
@MohammadMustaqeem You can check the index of each iteration, and not add a comma on first iteration. See example: play.golang.org/p/5544hc_0_g8 . Just be careful. Rendering JSON with templates will cause escaping issues. See the "C&D" address I added.Orford
thanks. I have solved the escaping issue by importing "text/template" instead of "html/template". play.golang.org/p/PXTNZGWx7YiChampignon
@MohammadMustaqeem Unfortunately you may now get invalid JSON, or even worse, injected JSON: play.golang.org/p/kd9bM_rpwyg . Using template for generating json is unwise, but if you have to, escape the JSON values with functions such as js (also in this example).Orford

© 2022 - 2024 — McMap. All rights reserved.