Assign a new value to an already initiated variable in template

6,937 views
Skip to first unread message

Accipiter Nisus

unread,
Oct 10, 2013, 5:54:31 AM10/10/13
to golan...@googlegroups.com
Hi,

What are the reasons why it is not possible to assign a new value to an already initiated variable in the text/template package?

Example where it is needed:

Let's say I have a list of people (json):

[
    {"name": "ANisus", "sex":"M"},
    {"name": "Sofia", "sex":"F"},
    {"name": "Anna", "sex":"F"}
]

Using the template package, I want to have this output:

Females:
Sofia
Anna

But the header "Females:" should only show in case there are actually any person with sex set to F.
If I could reassign a value, I would do the following:

{{$hasFemales := 0}}
{{range .}}{{if eq .sex "F"}}{{$hasFemales = 1}}{{end}}{{end}}
{{if $hasFemale}}Female:{{end}}


/ANisus

Jesse McNelis

unread,
Oct 10, 2013, 6:15:37 AM10/10/13
to Accipiter Nisus, golang-nuts


On 10/10/2013 8:54 PM, "Accipiter Nisus" <acci...@gmail.com> wrote:
>
> Hi,
>
> What are the reasons why it is not possible to assign a new value to an already initiated variable in the text/template package?
>

Templates aren't the place for doing complex logic. Do it before you pass the data to the template.

> {{$hasFemales := 0}}
> {{range .}}{{if eq .sex "F"}}{{$hasFemales = 1}}{{end}}{{end}}
> {{if $hasFemale}}Female:{{end}}
>
> Example: http://play.golang.org/p/T-Ekx7n9YQ

You can easily count the females before you pass the slice to the template and pass that in too.

Ibrahim M. Ghazal

unread,
Oct 10, 2013, 6:47:13 AM10/10/13
to Accipiter Nisus, golang-nuts
Actually, you *can* assign new values to variables: http://play.golang.org/p/GzXhsDFpom

package main

import (
"os"
"text/template"
)

func main() {
const tmpl = `
{{$foo := 0}}
$foo is {{$foo}}
{{$foo := 1}}
Now $foo is {{$foo}}
`
t := template.Must(template.New("tmpl").Parse(tmpl))
err := t.Execute(os.Stdout, nil)
if err != nil {
panic(err)
}
}


Output:

$foo is 0

Now $foo is 1

Accipiter Nisus

unread,
Oct 10, 2013, 7:24:38 AM10/10/13
to golan...@googlegroups.com, Accipiter Nisus
Well, what do you know.

But, it only works within the same scope. I think it is not so much reassigning a value as replacing the previous variable in the scope with a new one.
In my playground code, it doesn't work. $hasFemale in the outer scope remains unchanged.

Accipiter Nisus

unread,
Oct 10, 2013, 8:18:36 AM10/10/13
to golan...@googlegroups.com, Accipiter Nisus, jes...@jessta.id.au

Templates aren't the place for doing complex logic. Do it before you pass the data to the template.

Whether or not assigning a new value to a variable is considered complex logic might be up for discussion.

When the template package is used in a generic context (eg. Executing an arbitrary template file with an arbitrary json file), you might not have the luxury of doing precalculations.

/ANisus

Steven Blenkinsop

unread,
Oct 10, 2013, 10:52:20 PM10/10/13
to Accipiter Nisus, golang-nuts, Jesse McNelis
You could do something like this if you had to:


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

sorenhoyer...@gmail.com

unread,
Mar 11, 2015, 8:33:41 AM3/11/15
to golan...@googlegroups.com
I don't think something like this is "complex logic" and when developing a generic application like a CMS, this functionality would be very handy to have, like we can with Razor.

This is the biggest (and only) problems I have with Go. I simply do not understand why this functionality has not been implemented yet.

ld...@google.com

unread,
Dec 19, 2016, 1:31:17 AM12/19/16
to golang-nuts
encountered same problem, as it seems still an open issue, cannot change value of an existing variable inside of loop/if in template 
https://github.com/golang/go/issues/10608
...
      {{$deprecated := false}}
      {{range $depre_audit := $depre_audits}}
      {{if eq $audit_name $depre_audit}}
      {{$deprecated := true}}   ------> this line doesn't work beyond end
      <span class="audit_name_chart">{{$audit_name}} - deprecated</span>
      {{end}}
      {{end}}
      {{if not $deprecated}}
      <span class="audit_name_chart">{{$audit_name}}</span>
      {{end}}

Aliaksandr Valialkin

unread,
Dec 19, 2016, 2:22:35 AM12/19/16
to golang-nuts
FYI, complex logic may be easily implemented with alternative template engines like https://github.com/valyala/quicktemplate .

whut....@gmail.com

unread,
Feb 22, 2018, 12:42:04 AM2/22/18
to golang-nuts
Thanks for this example!
I realized that to modify a variable I have to add a "var" function to return pointer of an object,  then I can use a "set" function to modify it.
And in the beginning I also provided "get" function to return the value referenced by the pointer, however later I suddenly found that I don't need to do that, go template will automatically return the object itself, rather than the pointer.
So this is my version https://play.golang.org/p/C1MtTKvdmGT
I think it is more concise and elegant than the original example :-)
Thanks so much for inspiring me!
Reply all
Reply to author
Forward
0 new messages