Go template/html pass variable to nested template [duplicate] - html

We can define template name via {{define "home"}}, and then load it in other (parent) template via {{template "home"}}.
How I can load template via variable value {{template .TemplateName}}. Or it's impossible?

Unfortunately you can't.
The syntax of the {{template}} action:
{{template "name"}}
The template with the specified name is executed with nil data.
{{template "name" pipeline}}
The template with the specified name is executed with dot set
to the value of the pipeline.
The name of the template to be included is a constant string, it is not a pipeline which could vary during execution based on parameters.
If the allowed syntax would be:
{{template pipeline}}
then you could use something like {{template .TemplName}} but since the syntax only allows a constant string, you can't.
Reasoning from Rob why dynamic template invocation is not allowed (source):
We want the template language to be statically analyzable so the context of a template's invocation is clear, checkable, and lockdownable. If an invocation point is totally dynamic, this can't be done. Similarly, if a template can belong to multiple sets, its context can differ between sets in a way that would require all sets to be analyzed simultaneously. Since both these constraints are easy to work around if you want to, at the cost of losing those static checks in a higher-level package, it seemed wise to control the situation in the base template implementation. A higher-level package, such as a hypothetical HTML-only wrapper, can guarantee no workarounds more easily if the constraints are clear.
Alternative #1: Execute Includable Template First
What you can do is execute the template you would want to include first, and insert the result where you want to include it. You can use special types not to escape the result of the inner template when inserting, for example html.HTML in case of HTML templates.
See this example:
func main() {
t := template.Must(template.New("t").Parse(t))
template.Must(t.New("t1").Parse(t1))
params := struct {
Name string
Value interface{}
}{"t1", nil}
b := bytes.Buffer{}
t.ExecuteTemplate(&b, params.Name, nil)
params.Value = template.HTML(b.String())
t.Execute(os.Stdout, params)
}
const t = `<html><body>
Now I will include template with name: {{.Name}}
{{.Value}}
</body>/html>`
const t1 = `I'm template <b>t1</b>.`
Output:
<html><body>
Now I will include template with name: t1
I'm template <b>t1</b>.
</body>/html>
Try it on the Go Playground.
The result of template t1 was inserted unescaped. If you leave out template.HTML:
params.Value = b.String()
t1 would be inserted escaped, like this:
<html><body>
Now I will include template with name: t1
I'm template <b>t1</b>.
</body>/html>
Alternative #2: Restructure Templates
You can restructure your templates not to be in situations where you would want to include a template with varying names.
Example: you might want to create pages where you have a page template something like this:
<html><body>
Title, headers etc.
{{template .Page}}
Footers
</body></html>
You can restructure it to be something like this:
header template:
<html><body>
Title, headers, etc.
footer template:
Footers
</body></html
And your page templates would include header and footer like this:
{{template "header" .}}
Page content comes here.
{{template "footer" .}}
Alternative #3: Use {{if}} action and predefined names
If you know the template names prior and it is not an exhausting list, you can use the {{if}} template action to include the desired template. Example:
{{if eq .Name "page1"}}
{{template "page1" .}}
{{else if eq .Name "page2"}}
{{template "page2" .}}
...
{{end}}
Alternative #4: Modifying the static template text
The idea here is that you could modify the static text of the outer template manually and insert the name of the inner template you want to include.
The downside of this method is that after inserting the name of the inner template, you have to re-parse the template, so I don't recommend this.

Related

Content Projection with Go HTML Templates [duplicate]

How do I get nested templates like Jinja has in the python runtime. TBC what I mean is how do I have a bunch of templates inherit from a base templates, just filing in blocks of the base templates, like Jinja/django-templates does. Is it possible using just html/template in the standard library.
If that is not a possibility, what are my alternatives. Mustache seems to be an option but would I then be missing out on those nice subtle features of html/template like the context sensitive escaping etc.? What other alternatives are ther?
(Environment: Google App Engin, Go runtime v1, Dev - Mac OSx lion)
Thanks for reading.
Yes it is possible. A html.Template is actually a set of template files. If you execute a defined block in this set, it has access to all the other blocks defined in this set.
If you create a map of such template sets on your own, you have basically the same flexibility that Jinja / Django offers. The only difference is that the html/template package has no direct access to the file system, so you have to parse and compose the templates on your own.
Consider the following example with two different pages ("index.html" and "other.html") that both inherit from "base.html":
// Content of base.html:
{{define "base"}}<html>
<head>{{template "head" .}}</head>
<body>{{template "body" .}}</body>
</html>{{end}}
// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}
// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}
And the following map of template sets:
tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))
You can now render your "index.html" page by calling
tmpl["index.html"].Execute("base", data)
and you can render your "other.html" page by calling
tmpl["other.html"].Execute("base", data)
With some tricks (e.g. a consistent naming convention of your template files), it's even possible to generate the tmpl map automatically.
note, when you execute your base template, you must pass values down to the child templates, here I simply pass ".", so that everything is passed down.
template one displays {{.}}
{{define "base"}}
<html>
<div class="container">
{{.}}
{{template "content" .}}
</div>
</body>
</html>
{{end}}
template two displays {{.domains}} that's passed into the parent.
{{define "content"}}
{{.domains}}
{{end}}
Note, if we used {{template "content"}} instead of {{template "content" .}}, .domains wouldn't be accessible from the content template.
DomainsData := make(map[string]interface{})
DomainsData["domains"] = domains.Domains
if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
having worked with other template packages, now a days I mostly work with standard html/template package, I guess I was naive to not appreciate the simplicity it provides and other goodies. I use a very similar approach to accepted answer with following changes
you don't need to wrap your layouts with additional base template, a template block is created for every parsed file so in this case it is redundant, I also like to use the block action provided in new version of go, which allows you to have default block content in case you don't provide one in child templates
// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>
and you page templates can be the same as
// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}
// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}
now to execute the templates you need to call it like so
tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)
Use Pongo, which is a super-set of Go Templates that supports the {{extends}} and {{block}} tags for template inheritance, just like Django.
I've been coming back to this answer for days, finally bit the bullet and wrote a small abstraction layer / pre processor for this. It basically:
Adds the 'extends' keyword to templates.
Allows overriding 'define' calls (thus default values for greggory are possible)
Allows non defined 'template' calls, they just give an empty string
Sets the default value of . in 'template' calls to . of the parent
https://github.com/daemonl/go_sweetpl

reusing handlebars & panini partials with different data

I've a number of 'building blocks' I've created of my own to use when templating a site and I'm wondering how I could use Panini to re-use partials on the same page, with different data.
Say for example I have a partial which basically adds a h1 tag followed by a single p tag but I want to be able to re-use that same partial on the same page with different data each time.
This is the content of the partial file for example;
<h1> {{ h1Header }}</h1>
<p> {{ pParagraph }} </p>
The Frontmatter data in the Index file;
---
h1Header: Hello!
pParagraph: This is some text.
---
And this to call the partial into action;
{{> partial }}
Unless I'm doing something fundamentally wrong the way I'm using it at the moment would mean I'd have to create several different partials for each possible outcome.
I was wondering if there was some way of sending arguments etc. If someone can point me in the right direction with even the simplest of examples just to get a feel of what I can do and what to look into I'd be grateful.
You can pass data to your partials passing a context or parameters to your partial. You can pass different data every-time you render the partial, according to the manual.
Having a partial called test:
<h1>{{foo}}</h1>
You can render it with specific data:
{{> test foo="bar"}}
{{> test foo="foobar"}}
Which results in
<h1>foo</h1>
<h1>foobar</h1>

Twig escaping HTML and rendering as raw

I hope someone can assist me on this issue.
I am pulling details from a database to display on a twig template (using Symfony2) but the way in which it is saved in the db makes it difficult to interpret the HTML.
Basically, the HTML tags are already translated as entities in the table, e.g.:
<p>Bach Flower Crab Apple Remedy:&nbsp;the "cleansing" Remedy can be used both internally and externally&nbsp;</p><p><strong>
And so on. I have researched the rendering options in twig and tried the following (based on me rendering a loop of product descriptions):
{% set strategy = 'html' %}
{% autoescape 'html' %}
{{ product.description|escape('html')|raw }}
{% endautoescape %}
and also just:
{{ product.description|raw }}
The first method just echoes the existing content (as entities) and the second method just renders the HTML tags to the page as follows:
<p>Bach Flower Crab Apple Remedy: the "cleansing" Remedy can be used both internally and externally.</p><p><strong>...
So, as you can see, I cannot find a way to actually interpret the HTML tags in order to display the description as it should be.
Is there a way to do this? I can't do it in the PHP as all it's doing is sending an object to the template which is looped through:
public function showAction(Request $request, $store_id=0)
{
$max = 1000;
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
$products = $repository->getProductsByStoreId($store_id,$max);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$products,
$request->query->get('page', 1),
20
);
$return['products'] = $pagination;
$return['categories'] = $this->getCategories();
return $this->render('AppBundle:tables:productstable.html.twig', $return);
}
Your core issue is that you do not have HTML in your database to begin with. At best Twig could be outputting some HTML entities, which will render visibly as "<p>...", and at "worst" Twig will escape the text to render it accurately as it actually is, which is "<p>...". Expecting Twig to output actual HTML which will render a paragraph is unrealistic, since that's not what your original data contains at all.
You'll have to HTML-decode that text in PHP first, and then output it in Twig with ..|raw. raw means that Twig will output it as is without further escaping it. Since it's nonsense to get the data from the database to then html_entity_decode it, you need to fix your data input here! Don't HTML encode data which is going into the database, it serves no purpose.
I think you have to write custom escaper plugin to decode html entities and use it like this:
{{ product.description|myawesomehtmlentitiesdecoder|raw }}
http://twig.sensiolabs.org/doc/filters/escape.html#custom-escapers for reference.
But generally, it's better to store HTML in database and then apply needed security filters on output.

Golang: custom template function "capture"

I want to write template function like Smarty's capture.
How can I capture html inside
{{capture}}
...
{{/capture}}
How to do this?
{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}
ONE TWO
You would do it in the application: Use a template for the HTML snippet you want to capture, render it, save it to a string and use it in subsequent template rendering.

URL encoding on Django Template

I have this anchor link:
{{title}}
Sometimes, this title has some content with + (add operator) like:
"Django + Python"
But when it is directly placed on anchor links, the url delivered will be:
http://127.0.0.1:8080/question/tag/1/1/?list_id=Django + Python
Which will eventually cause problem on the retrieval as the url decoder thought the list_id GET = DjangoPython.
So, does anyone knows how to avoid this issue? Note that I do not want to change anchor links to input buttons.
Instead of
{{ title }}
do
{{title|urlencode}}
Instead of hardcoding the URL and building the querystring in the template by concatenating the title context item, consider simplifying it a bit by using django.core.urlresolvers.reverse() and specifying a named URL from the relevant urls.py file. Makes for a clean design when you don't have to worry about URLs changing! Imagine the headache of all the scattered HREFs you'd have to change, versus simply assigning a context variable from the view set to the result of the reverse call. The querystring can be added nicely in the view too, without having to worry about some of the often strange template parsing rules. Note that the urllib.urlencode function acts completely differently to the template filter of the same name; don't get confused! It can be used as follows:
# If the entry in URLConf has named capture groups such as ?<pk>,
# pass a dict as kwargs parameter instead.
url = reverse('your-named-url', args=(1, 1)) # e.g '/question/tag/1/1/'
# Encodes as form data to 'list_id=Django+%2B+Python'
querystring = urllib.urlencode({'list_id': 'Django + Python'})
context['question_url'] = '{}?{}'.format(url, querystring)
Then, in the template it can be as simple as href="{{ question_url }}". It might seem like more work, but it can pay off very quickly and it's a much better separation of concerns. Normally I'd use the {% url "your-named-url" %} template tag, but it doesn't currently handle querystrings nicely -- as in, not in the same manner as it deals with URL args and kwargs defined in URLConf.