Variables inside golang templates

What is the namespace of variables inside html/text templates? I thought the $x variable could change the value inside the template, but this example shows me that I cannot.

I failed when I tried to group tournaments by year - something like this ( http://play.golang.org/p/EX1Aut_ULD ):

 package main import ( "fmt" "os" "text/template" "time" ) func main() { tournaments := []struct { Place string Date time.Time }{ // for clarity - date is sorted, we don't need sort it again {"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)}, {"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)}, {"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)}, } t, err := template.New("").Parse(' {{$prev_year:=0}} {{range .}} {{with .Date}} {{$year:=.Year}} {{if ne $year $prev_year}} Actions in year {{$year}}: {{$prev_year:=$year}} {{end}} {{end}} {{.Place}}, {{.Date}} {{end}} ') if err != nil { panic(err) } err = t.Execute(os.Stdout, tournaments) if err != nil { fmt.Println("executing template:", err) } } 
+11
source share
3 answers

Change: see fooobar.com/questions/1233292 / ... for a more current answer.


Original answer:

https://golang.org/pkg/text/template/#hdr-Variables :

The scope of the variable extends to the "end" action of the control structure ("if", "with" or "range") in which it is declared, or to the end of the template if there is no such control structure.

Thus, the $prev_year you defined with {{$prev_year:=$year}} is valid only until ... the next line ( {{end}} ).

There seems to be no way around this.

The β€œright” way to do this is to remove this logic from the template and do the grouping in Go code.

Here is a working example: https://play.golang.org/p/DZoSXo9WQR

 package main import ( "fmt" "os" "text/template" "time" ) type Tournament struct { Place string Date time.Time } type TournamentGroup struct { Year int Tournaments []Tournament } func groupTournamentsByYear(tournaments []Tournament) []TournamentGroup { if len(tournaments) == 0 { return nil } result := []TournamentGroup{ { Year: tournaments[0].Date.Year(), Tournaments: make([]Tournament, 0, 1), }, } i := 0 for _, tournament := range tournaments { year := tournament.Date.Year() if result[i].Year == year { // Add to existing group result[i].Tournaments = append(result[i].Tournaments, tournament) } else { // New group result = append(result, TournamentGroup{ Year: year, Tournaments: []Tournament{ tournament, }, }) i++ } } return result } func main() { tournaments := []Tournament{ // for clarity - date is sorted, we don't need sort it again {"Town1", time.Date(2015, time.November, 10, 23, 0, 0, 0, time.Local)}, {"Town2", time.Date(2015, time.October, 10, 23, 0, 0, 0, time.Local)}, {"Town3", time.Date(2014, time.November, 10, 23, 0, 0, 0, time.Local)}, } t, err := template.New("").Parse(' {{$prev_year:=0}} {{range .}} Actions in year {{.Year}}: {{range .Tournaments}} {{.Place}}, {{.Date}} {{end}} {{end}} ') if err != nil { panic(err) } err = t.Execute(os.Stdout, groupTournamentsByYear(tournaments)) if err != nil { fmt.Println("executing template:", err) } } 
+11
source

In go1.11 text / template and, therefore, html / template, it became possible to set the value of existing variables , which means that the source code can be made to work with one very small modification.

+ Change

 {{$prev_year:=$year}} 

to

 {{$prev_year = $year}} 

Playground

+4
source

As mentioned in this answer, the scope of this reassignment variable ends in the {{end}} block. Therefore, using standard variables only , the problem is not solved and it must be solved inside the Go program executing the template.

In some frameworks, however, this is not so simple (e.g. protoc-gen-gotemplate).

The Sprig library adds additional functionality to the standard template language. One of them is volatile cards, which can be used as follows:

 // init the dictionary (you can init it without initial key/values as well) {{$myVar := dict "key" "value"}} // getting the "key" from the dictionary (returns array) and then fetching the first element from that array {{pluck "key" $myVar | first}} // conditional update block {{if eq "some" "some"}} // the $_ seems necessary because Go template functions need to return something {{$_ := set $myVar "key" "newValue"}} {{end}} // print out the updated value {{pluck "key" $myVar | first}} 

This small example prints:

 value newValue 

A pragmatic approach would be to use one dictionary for all mutable variables and store them under its corresponding variable name as a key.

Link:

+2
source

Source: https://habr.com/ru/post/1233292/


All Articles