Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call other templates with dynamic name

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.

like image 519
Brad Peabody Avatar asked Dec 21 '13 07:12

Brad Peabody


People also ask

How do I call a subtemplate from a main template?

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.

How do I create a myaddress subtemplate 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.

How do I replace the name of a namespace in a 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.

How to make your arm templates more dynamic?

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.


2 Answers

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)
    }

}
like image 105
Brad Peabody Avatar answered Sep 23 '22 00:09

Brad Peabody


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
}
like image 20
Caleb Avatar answered Sep 26 '22 00:09

Caleb