Golang/Revel template engine template with variable - go

Is there a way to pass a variable that was iterated over into a Golang/Revel template?
For example, in "header.html", I have
{{range .templates}}
{{template "something" .}}
{{end}}
How can I use current index from the array as an argument to template? I tried embedding another {{.}} as shown in the Revel examples, but that leads to a template compliation error. Would the variable be something like $i?
For example, iterating through in Revel is done like so
{{range .messages}}
<p>{{.}}</p>
{{end}}
However, I read that the . means nil.... how does this work in Revel?

If I understand your question correctly, you can use the range built-in to get the index, and then pass it to the template like this:
{{range $i, $t := .templates}}
{{template "Template.html" $i}}
{{end}}
So if the templates variable was defined like this:
templates := []string{"One", "Two"}
and Template.html contains:
This is from Template.html: {{ . }}<br>
Then the final output will be:
This is from Template.html: 0<br>
This is from Template.html: 1<br>

Related

Is it possible to access value in a list in Revel Template [duplicate]

This question already has answers here:
How to index a slice element?
(2 answers)
Closed 4 months ago.
{{ range .foo }}
{{end}}
.
{{range $index, $element := .foo }}
{{end}}
I'm aware that you can use this like for loop, but is there any other way to access a value in array directly like {{ foo[2] }} in Revel Template?
I've read this Revel documentation but doesn't seem to find any.
It is not Revel specific, indexing is included in the standard library templates:
{{index .foo 2}}

How to set a golang variable to a template variable

I am new to golang and want to understand how to assign a template variable in golang using the golang variable.
I am using go-swagger to generate go code.
Below is the piece of a customized template to generate my swagger client.
func demo() {
{{range .Operations}}
Value := main.CheckAvail(*{{.Package}}.{{ pascalize .Name }})
{{$value := .Value}}
{{if $value }}
{{ pascalize .Name }}
{{end}}
{{end}}
}
But it gives me the error that:
" <.Value>: can't evaluate field Value in type generator.GenOperation ".
How do I assign the value to the $value? Any help?
This is not possible. The template file is a wire frame for a go file. It just generates a file of go code, which is not executed yet.
All in {{ ... }} is evaluated, when the template is parsed. At this point, all text outside the curly braces is just plain text. After the (successful) execution of the template generation the generated text will be picked up by the go compiler and compiled (if it is correct go code).
In this case you cannot evaluate Value.

How to have short circuit with and/or in text/template

I have this Go template:
{{ if and $b.Trigger $b.Trigger.Name }}
Name is {{ $b.Trigger.Name }}.
{{ else }}
...other stuff...
{{ end }}
I'm trying to get this template to do:
if b.Trigger != nil && $b.Trigger.Name != "" { ...
however it doesn't work, because as text/template godoc says, both arguments to and/or functions are evaluated.
When the $b.Trigger.Name is evaluated, it errors out because $b.Trigger can be nil. So it returns error:
template: builds.html:24:46: executing "content" at <$b.Trigger.Name>: can't evaluate field Name in type *myType
I tried refactoring this to:
{{ if and (ne $b.Trigger nil) (ne $b.Trigger.Name "") }}
and weird enough, this fails as well, it says I can't compare $b.Trigger with nil, which doesn't make sense because that field is a pointer type:
template: builds.html:24:31: executing "content" at <ne $b.Trigger nil>: error calling ne: invalid type for comparison
Any ideas?
As Volker noted above, nest the ifs:
{{if $b.Trigger}}{{if $b.Trigger.Name}}
Name is {{ $b.Trigger.Name }}.
{{end}}{{end}}
Or, more succinctly:
{{with $b.Trigger}}{{with .Name}}
Name is {{.}}.
{{end}}{{end}}
Unfortunately, the above won't handle else clauses. Here's one (rather ugly) possibility:
{{$bTriggerName := ""}}
{{with $b.Trigger}}{{$bTriggerName = .Name}}{{end}}
{{with $bTriggerName}}
Name is {{.}}.
{{else}}
...other stuff...
{{end}}
I looked to see if gobuffalo/plush could do this more elegantly, but as of 2019-04-30 it cannot.
Here explains why all arguments are evaluated in a pipeline.
It is evaluated through go template functions
https://golang.org/pkg/text/template/#hdr-Functions

How to get a field by index in template?

I send a slice of articles into template. Each articlestruct is like:
type Article struct {
ID uint32 `db:"id" bson:"id,omitempty"`
Content string `db:"content" bson:"content"`
Author string `db:"author" bson:"author"`
...
}
I can loop over articles slice in a {{range $n := articles}} and get each {{$n.Content}} but what I want is to have only the first one (outside the range loop) to use in headline.
What I tried is:
{{index .articles.Content 0}}
But I get:
Template File Error: template: articles_list.tmpl:14:33: executing
"content" at <.articles.Content>: can't evaluate field Content in type
interface {}
If I just invoke
{{index .articles 0}}
It shows the whole article[0] object.
How can I fix this?
The index function access the nth element of the specified array, so writing
{{ index .articles.Content 0 }}
is essentially trying to write articles.Content[0]
You would want something akin to
{{ with $n := index .articles 0 }}{{ $n.Content }}{{ end }}
A more concise way is:
{{(index .articles.Content 0).Content }}
Which would be the equivalent of articles[0].Content.
{{(index .articles 0).Content}}

Defining a top level go template

Suppose that I have tow text files (go templates):
child.tmpl
TEXT1
Hello {{ . }}
top.tmpl
TEXT2
{{ template "child.tmpl" "argument"}}
the child.tmpl template is nested in top.tmpl
A typical program to parse them will be :
package main
import (
"os"
"text/template"
)
func main() {
t := template.Must(template.ParseFiles("child.tmpl", "top.tmpl")
t.ExecuteTemplate(os.Stdout, "top.tmpl", nil)
}
Is there any method the pass the template to be embedded in the top-level template as an argument using the {{ . }} notation ?
something like {{ template {{.}} "argument" }}
More generally, what is the best way to define a layout template so I can use it like a top-level template to multiple child templates ?
There are two accepted ways to solve your problem:
The first involves writing your own template-inclusion function and registering it as an template.FuncMap with your template through template.Funcs.
The other way is to use {{define xxx}} blocks in your child templates. Then you could have two different files that define the same template:
file1.html: {{define body}}...{{end}}
file2.html: {{define body}}...{{end}}
Parse the correct file depending on your needs and in your parent template just do {{template body "argument"}}.
In my opinion, the first option is more flexible.

Resources