-1

Given the below template:

{{ range $item := . }}
    {{ if $item.IsA}}
        Ok
    {{ else }}
        Fine
     {{ end }}
{{ end }}
Done!

When I render it using:

 t := template.New("test").Parse(_types)
 text, err := t.Execute(&buffer, strct)

The output is something like:

!empty line
!empty line
       Ok
!empty line
!empty line
Done! 

This means that if I want to format the text correctly, I have to re-write it as

{{ range $item := .}}{{ if $item.IsA }}OK{{ else }}{{ end }}{{ end }}
Done!

Then I get something like:

Ok
Done!

Which is the desired output.

Writing the template the second way is very unreadable and messy. Is there any way that we can write the template with proper indentation but somehow configure rendering in such a way that the template placeholders would not be converted to new lines, or their indentation would be ignored (so that the desired output would be generated)?

Edit: using {- ""} even makes the whole thing worse! Why? Please consider the following:

{{- range $item := . }}
    {{- if $item.IsA }}
        {{- "How many spaces??" -}}OK 
...

So let me put it in another way, is there any built-in post-processor available in golang for templates?

Arnold Zahrneinder
  • 4,788
  • 10
  • 40
  • 76

1 Answers1

0

I came across this solution after playing with templates for a while. In order to make the template cleaner, we can do one trick. Templates do accepts custom functions and the trick is to define an indentation function:

const _indent = "___START___"
_funcs = template.FuncMap {
    "Indent": func(indent int) string {
        str := bytes.NewBufferString(_indent)
        for i := 0; i < indent; i++ {
            str.WriteString(" ")
        }
        return str.String()
     },
 }

We can include a character as indentation as well but here I only need spaces. Then we need a post processor:

func PostProcess(strBuffer bytes.Buffer) bytes.Buffer {
    buffer := bytes.NewBufferString("")
    lines := strings.Split(strBuffer.String(), "\n")
    for _, line := range lines {
        tmp := strings.TrimLeftFunc(line, func(r rune) bool {
            return r == ' '
        })
        tmp = strings.TrimPrefix(tmp, _indent)
        buffer.WriteString(tmp)
    }
    return *buffer
}

Now we can write the markup as:

{{ range $i :=  . }}
    {{ if $i.IsOk }}
        {{ 4 | Indent }}OK
...

and we can run the PostProcess function on the rendered text. My PostProcess function does not eliminate empty lines, but we can add it easily as well.

This is way more readable than the {{- " " -}} syntax.

Arnold Zahrneinder
  • 4,788
  • 10
  • 40
  • 76