I do not see a way to call templates (text or html) with a dynamic name. Example:
This works:
{{template "Blah" .}}
This errors with "unexpected "$BlahVar" in template invocation":
{{$BlahVar := "Blah"}}
{{template $BlahVar .}}
The overall problem I'm trying to solve is that I need to render templates conditionally based on a configuration file - so I don't know the names of the templates ahead of time. Obviously I can put a function in the FuncMap which just does a separate template parsing and invocation and returns that result but was wondering if there is a Better Way.
There are two entries that you must make to call a subtemplate from a main template. To implement the subtemplate in a main template, you must make two entries in the main template: First, import the subtemplate file to the main template. The import syntax tells the BI Publisher engine where to find the Sub Template in the catalog.
Create a Sub Template in the catalog in the following location: Customer Reports/Templates. Upload this file to the Sub Template and save it as "Common Components" (BI Publisher assigns the object the .xsb extension). At runtime the contents of the MyAddress subtemplate are fetched and rendered in the layout of the main template.
The following section shows you how to modify a template to replace the name of a namespace with the "safe project name". Insert the parameter in one or more of the code files in the template. For example: In the vstemplate file for the template, locate the ProjectItem element that includes this file.
When you’re starting your journey on building ARM Templates we make them more dynamic by adding Parameters to the templates. When we start building our library of templates to be used in our organization this works great for most resources but not all. For instance, creating a VM you can typically simply use Parameters and Variables.
As a note on this and to follow up, I eventually ended up with two main answers to this question: 1) Try to avoid this. In several cases a simple if statement worked fine. 2) I was able to accomplish this using a function in the FuncMap that just does a separate rendering. It's not the greatest thing in the world, but it does work and solves the problem. Here is a full standalone demo that shows the idea:
package main
import (
"bytes"
"html/template"
"os"
)
func main() {
var err error
// our main template here calls a sub template
tpl := template.New("main")
// provide a func in the FuncMap which can access tpl to be able to look up templates
tpl.Funcs(map[string]interface{}{
"CallTemplate": func(name string, data interface{}) (ret template.HTML, err error) {
buf := bytes.NewBuffer([]byte{})
err = tpl.ExecuteTemplate(buf, name, data)
ret = template.HTML(buf.String())
return
},
})
// this is the main template
_, err = tpl.Parse(`
{{$Name := "examplesubtpl"}}
from main template
{{CallTemplate $Name .}}
`)
if err != nil {
panic(err)
}
// whatever code to dynamically figure out what templates to load
// a stub just to demonstrate
_, err = tpl.New("examplesubtpl").Parse(`
this is from examplesubtpl - see, it worked!
`)
if err != nil {
panic(err)
}
err = tpl.Execute(os.Stdout, map[string]interface{}{})
if err != nil {
panic(err)
}
}
Another way, though perhaps not a better way, would be to have separate template files which all provide the same named template. For example suppose you have a shared layout for a web page:
<html>
...
<body>
{{template "body" .}}
</body>
</html>
In each page you do this:
{{define "body"}}
This will be in the body
{{end}}
And then merge them in code:
func compileTemplate(layout, name string) (*template.Template, error) {
tpl := template.New(name)
tpl, err := tpl.ParseFiles(
"views/layouts/"+layout+".htm",
"views/"+name+".htm",
)
if err != nil {
return nil, err
}
return tpl, nil
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With