Moo
Moo

Reputation: 97

How to trim empty rows in Go templates?

go version go1.16.3 windows/amd64

I use the template/html package. If I set a variable into html,

Example

  {{range $kk, $vv := .Users -}}
      {{if eq $vv.Id $performedBy}}
          {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
      {{- end}}
  {{- end}}

Whenever I fill a variable in a range, it writes me an empty row. What can I do to prevent this from happening again?

Upvotes: 4

Views: 3441

Answers (1)

icza
icza

Reputation: 418137

Package doc of text/template, Text and spaces:

By default, all text between actions is copied verbatim when the template is executed. [...]

However, to aid in formatting template source code, if an action's left delimiter (by default "{{") is followed immediately by a minus sign and white space, all trailing white space is trimmed from the immediately preceding text. Similarly, if the right delimiter ("}}") is preceded by white space and a minus sign, all leading white space is trimmed from the immediately following text. In these trim markers, the white space must be present: "{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while "{{-3}}" parses as an action containing the number -3.

TLDR; all (white) space in the template is preserved between actions. If you don't want them, you may use a minus - sign after the opening delimeter or before the closing delimeter of the action "in place" to trim the leading or trailing white spaces.

You have to indent your template how you want the output, or use the - sign to trim the formatting indentation.

The main problem with your {{if}} action:

  {{if eq $vv.Id $performedBy}}
      {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
  {{- end}}

There is a newline after the closing delimeter of {{if}}, which will be preserved if the body of {{if}} is executed. The - sign in {{- end}} only trims the newline preceeding this {{- end}} (the one being after the variable assignments), but not that being at the end of {{if}}.

For example using this template:

const src = `{{$performedBy := "1"}}{{$pSurname := ""}}{{$pName := "" -}}
{{range $kk, $vv := .Users -}}
User idx: {{$kk}}
{{if eq $vv.Id $performedBy -}}
    {{- $pSurname = $vv.ContactData.Surname -}} {{- $pName = $vv.ContactData.Name -}}
{{- end -}}
{{- end}}`

Testing it:

type CData struct {
    Surname, Name string
}

type User struct {
    Id          string
    ContactData CData
}

func main() {
    t := template.Must(template.New("").Parse(src))

    p := map[string]interface{}{
        "Users": []User{
            {Id: "1", ContactData: CData{"Foo", "Bar"}},
            {Id: "2", ContactData: CData{"Foo2", "Bar2"}},
            {Id: "1", ContactData: CData{"Foo3", "Bar3"}},
            {Id: "4", ContactData: CData{"Foo4", "Bar4"}},
        },
    }

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

Output (try it on the Go Playground):

User idx: 0
User idx: 1
User idx: 2
User idx: 3

Upvotes: 7

Related Questions