3

This is partly a follow-up to my earlier question. The problem I'm trying to solve now is converting Jinja2 macros with arguments, e.g., something like

{% macro example(arg1, arg2) %}
{% if arg1 %}
   do something with arg1 and arg2
{% endif %}
{% endmacro %}

AFAICT, in Go, the nearest equivalent are nested templates, e.g.,

{{define "example"}}
{{if .Arg1}}
    do something with .Arg1 and .Arg2
{{end}}
{{end}}

However, whereas in Jinja arg1 and arg2 are what I'd call true arguments, i.e., when you call the example macro you invoke it as {{example(par1, par2)}}, in Go, you use {{template "example" .}} and the dot is analogous in my mind to an undefined (or not clearly defined) global workspace.

The problem is when those arguments are defined in the calling template, i.e., let's say that in Jinja it's called as {{example("somestring", "another")}} in one template and two other strings in another template. I thought I could use variables to pass the information, e.g., {{$arg1 := "somestring"}} and then invoke the template, or even define the variable in the same action as the invocation, but Go keeps complaining undefined variable "$arg1" so it doesn't seem to be possible.

I know I can "push" the definition of the strings to the calling Go code, but aside from complicating the calling tree, this doesn't feel right because after all the template is presentation code and those strings are part of the presentation, not the business logic. And it's not just string arguments, there are (a) instances of formatting functions (like upper() and lower()--I know I can define them in a funcmap) and (b) HTML formatting macros that, for example, take a CSS class attribute as one of the arguments.

Is there any hope for a solution with Go templates or should I just give up and use something else?

Joe Abbate
  • 1,692
  • 1
  • 13
  • 19
  • 2
    If you want something similar in nature to Jinja2 (though actually modeled off Django) then Pongo2 is a good choice. https://github.com/flosch/pongo2 – sberry Aug 13 '19 at 03:16
  • I wasn't expressly looking for a (more or less) direct replacement for Jinja2, but I guess I'll give Pongo2 a try, since it does look like the path of least resistance. Thanks. – Joe Abbate Aug 13 '19 at 03:38
  • Are you asking how to pass (multiple) data to a template invocation? Possible duplicate [Golang pass multiple values from template to template?](https://stackoverflow.com/questions/49473199/golang-pass-multiple-values-from-template-to-template/49475057#49475057) – icza Aug 13 '19 at 07:06
  • I personally maintain a number of functions and [pass them to the engine as a map of functions](https://golang.org/pkg/text/template/#FuncMap). – Markus W Mahlberg Aug 13 '19 at 14:39
  • @icza No, I'm not asking that. I know one can pass data to a template invocation in a struct defined in the calling Go code. But in Jinja2 (and Django templates, if I'm not mistaken) it's possible to call a macro (equivalent to a Go template) with constants strings (or numbers) as shown above. In Go, it appears you *have* to put those constants in the calling Go code, *not* in the template. – Joe Abbate Aug 13 '19 at 22:50
  • @MarkusWMahlberg Yes, I already have a map of functions too. But in Jinja2/Django templates you can invoke Python object methods directly, e.g., `aString.upper()` or use some 50 filters (equivalent to Go template predefined global functions--less than 20). – Joe Abbate Aug 13 '19 at 23:14
  • I bet this is by design: "Why should we clutter the engine with 50 filters of which 99% might turn out useless? Developer knows best what filters he or she needs." – Markus W Mahlberg Aug 14 '19 at 08:26
  • @MarkusWMahlberg Yes maybe it's by design, but sometimes the lack of certain features is *very* annoying. For example, there doesn't appear to be any way to do something different on the last element of a slice. I think this is not uncommon. Say you have a list of some kind and you want to separate the elements with commas, or perhaps a slice of URL/text pairs where you only want to show the text for the last one. Getting the length of the slice doesn't help, because you want length - 1 (but you *can't* substract!). So you have to write a 'dec' function? – Joe Abbate Aug 21 '19 at 01:44

1 Answers1

4

Go templates are intentionally pretty basic. You're going to find that most of the time when you're looking for something that doesn't seem possible, you probably will end up solving it with a golang function. It helps keep templates simpler and pushes code into golang functions which are far more testable.

https://golang.org/pkg/html/template/#Template.Funcs

Alternatively, there are a number of alternative templating engines that are more full featured.

Liyan Chang
  • 7,721
  • 3
  • 39
  • 59
  • I took a quick look at pongo2 mentioned above, but decided to continue using bare Go templates (with functions of course) for now. – Joe Abbate Sep 04 '19 at 03:21