In order to use revel's even keyword in templates I would like to get the index of a map entry when iterating with range. Is there any way to do so?
My map has the structure:
map[string][]string
When we execute the call to mymap['key'] we get back two distinct values, the first of which is the value of the key and the second is a bool value which represents whether or not the given key exists within the map. This second value is what we use to check if a given key exists in the if statement on line 13.
A Simple way to achieve index while looping through a map:
package main
import (
"fmt"
)
func main() {
mm := map[string]int{"xx" : 1, "gg" : 2}
cnt := 0
for a, b:= range mm{
fmt.Println("a", a, "b",b, "c" , cnt)
cnt++
}
fmt.Println("Hello, playground")
}
And prints:
a xx b 1 c 0
a gg b 2 c 1
Hello, playground
You can't do this only with template actions, but you may register a function which provides the necessary help.
You may register a function which returns a function (closure), which alternates its return value whenever called (exactly how "odd" and "even" indices alternate):
func isEven() func() bool {
e := false
return func() bool {
e = !e
return e
}
}
I named it isEven() to not collide with ravel's even(). Using it:
func main() {
t := template.Must(template.New("").Funcs(template.FuncMap{
"isEven": isEven,
}).Parse(templ))
m := map[string]string{
"a": "A", "b": "B", "c": "C", "d": "D",
}
if err := t.Execute(os.Stdout, m); err != nil {
panic(err)
}
}
const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
[even:{{call $e}}] key={{$k}}; value={{$v}}
{{end}}`
Output (try it on the Go Playground):
[even:true] key=a; value=A
[even:false] key=b; value=B
[even:true] key=c; value=C
[even:false] key=d; value=D
If you want different output for odd and even iterations, you can call $e in an {{if}} action, like this:
const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
[{{if call $e}}even{{else}}odd {{end}}] key={{$k}}; value={{$v}}
{{end}}`
Output of this (try it on the Go Playground):
[even] key=a; value=A
[odd ] key=b; value=B
[even] key=c; value=C
[odd ] key=d; value=D
This template action:
{{$e := isEven}}
Creates a new template variable named $e, and its value will be the result (return value) of the isEven() function call. isEven() returns a function value, a closure that has access to a local variable e of type bool. When later you do {{call $e}}, you're not calling the isEven() Go function, but the function it returned (the closure) and is stored in $e. That closure has a reference to the local bool variable e, it is not "freed" until the function returned by isEvent() is accessible.
So whenever you do {{call $e}}, it calls the closure, which "has" an e variable of type bool, whose value is retained between calls of this $e.
If you would call isEvent in the template again, that would return a new function (closure), wrapping a new instance of the local variable e, being independent of the first wrapped variable of the closure returned by the first isEvent() call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With