0

Is there a way for me to define that when I just output a value in Go html templates the way the formatting is done instead of it printing a string representation without having to call a function to explicitcly convert it?

For example, let's say I have a type Person and I have a template with just {{.}} I want it to automatically create a link to that person's page but if I use the same template and passed a value of a different type some other HTML will be generated.

What I don't want to do is having to write something like {{.HTML}} or {{. | html}}. I'm already aware that these are possible but my question is specifically about how to avoid those.

I've played around with the thought of Person.String() having return the HTML code somehow without it being escaped but besides not getting that to work it also seems like an ugly solution.

Another solution I've thought about is to just pass everything as HTML into the template but then I couldn't access the attributes anymore (like {{.name}} to output just the name) and I'd also have to convert everything into HTML just in case it's used in the template.

Jimmy R.T.
  • 1,314
  • 1
  • 10
  • 13

1 Answers1

2

Create a method that returns an template.HTML type. i.e.:

func (p *Person) HTML() template.HTML {
    return fmt.Sprintf(`<a href="/person/%v">%s</a>`, p.id, template.HTMLEscapeString(p.name))
}

Then in your template:

{{ .HTML }}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Should have clarified that the template just having `{{.}}` in it is what I'm looking for, the problem with `toHTML` having to implement every type not actually being the issue – Jimmy R.T. Jan 27 '21 at 13:35
  • Then `{{ .HTML }}` – Jonathan Hall Jan 27 '21 at 13:36
  • but I don't want there to be a `HTML` appended, it should turn into HTML with just `{{.}}` – Jimmy R.T. Jan 27 '21 at 13:40
  • That's not an option, unless `.` represents an HTML string, but it doesn't. It's an struct instance, in your example. – Jonathan Hall Jan 27 '21 at 13:42
  • Is there an actual problem you're trying to solve here? Or do you think that `.HTML` is just ugly somehow? Maybe I don't understand your request. – Jonathan Hall Jan 27 '21 at 13:43
  • Two things: I find the `.HTML` ugly and I don't wanna one time write `{{.HTML}}` for `Person` type and another time write `{{.}}` when the type is `string` or `int`. The same template needs to work regardless of the type basically – Jimmy R.T. Jan 27 '21 at 13:47
  • Well, you're going to just have to get over `.HTML` feeling "ugly". Unfortunately, that's not something that Go templates will accomodate. As for needing a method that works for everything: Your typeswitch approach is probably the only way to work with truly _any_ type. – Jonathan Hall Jan 27 '21 at 13:51
  • 2
    May be not `{{. | html}}` but `{{. | pretty}}` where the particular implementation registered in the template as that `pretty` function would do different things: that is, have one for HTML and another one (or more) for plain text template(s). – kostix Jan 27 '21 at 13:54