the html/template module has a define/template feature that im trying to use to make it easier to change only one file that contains the global base of my website but its not working as intended.
base.html:
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
<body>
{{template "content"}}
</body>
</html>
{{end}}
index.html:
{{template "base"}}
{{define "content"}}
I'm page 1
{{end}}
blog.html:
{{template "base"}}
{{define "content"}}
I'm page 2
{{end}}
I expect to get I'm page 1 when i call index.html and I'm page 2 when i call blog.html but with both files i get I'm page 1 as the output. (i don't know what a dot at the end of template does but all combinations of that don't work aswell).
You cannot redefine and replace templates like that. Do the reverse: define index.html and blog.html as page1 and page2 respectively, import common header.html and footer.html into those.
Related
I'm using Go 1.19 with the built-in HTML template engine. Is there a way to test if a block is defined in a particular template file?
Specifically, I want to implement optional header entries in the Go HTML template.
I have a general layout template that includes a content template when rendered.
I want to implement as below...
Currently, the <meta name="description" content="{{block "description" .}}{{end}}"> result in an empty description tag. I'd like to not have the tag at all if there is nothing in it.
Any ideas?
layout.gohtml (simplified)[updated]
<html>
<head>
<title>{{block "title" .}}The Title{{end}}</title>
{{if .renderDescription}}
<meta name="description" content="{{template "description"}}">
{{end}
</head>
<body>
<header></header>
{{template "content" .}}
<footer></footer>
</body>
</html>
content1.gohtml
{{define "title"}}The 2hO Network{{end}}
{{define "description"}}An options description{{end}}
{{define "content"}}
Vestibulum ante ipsum primis in faucibus...
{{end}}
content2.gohtml
{{define "title"}}The 2hO Network{{end}}
{{define "content"}}
Vestibulum ante ipsum primis in faucibus...
{{end}}
Templates are designed to be statically analyzable. This means if you don't have a description template, you'll get an error when parsing the templates.
Instead use an {{if}} action to check if the description template needs to be rendered. The description template maybe empty.
For example:
{{if .renderDescription}}
{{template "description"}}
{{end}}
{{define "description"}}description content{{end}}
If you have to check the .renderDescription in many places, you may also move the check (the {{if}} action) into the template, so you can unconditionally use {{template}} (but you still have to provide a pipeline that contains the condition):
{{template "description" .}}
{{define "description"}}
{{if .renderDescription}}
description content
{{end}}
{{end}}
Notes:
The {{block}} action is not to include a template, it is to define and include a template. To include a template defined elsewhere, use {{template}}.
You also have to change your template structuring. Instead of having a "frame" template embedding a "content", define "header" and "footer" templates, and have each page have its own template, which include "header", the content and "footer".
Is it possible for me to set a variable in a template file {{$title := "Login"}} then parse it through to another file included using {{template "header" .}}?
An example of what I'm attempting:
header.tmpl
{{define "header"}}
<title>{{.title}}</title>
{{end}}
login.tmpl
{{define "login"}}
<html>
<head>
{{$title := "Login"}}
{{template "header" .}}
</head>
<body>
Login Body!
</body>
</html>
{{end}}
How can I parse this custom $title variable I made through to my header template?
As #zzn said, it's not possible to refer to a variable in one template from a different one.
One way to achieve what you want is to define a template – that will pass through from one template to another.
header.html
{{define "header"}}
<title>{{template "title"}}</title>
{{end}}
login.html
{{define "title"}}Login{{end}}
{{define "login"}}
<html>
<head>
{{template "header" .}}
</head>
<body>
Login Body!
</body>
</html>
{{end}}
You could also pass through the title as the pipeline when you invoke the "header" template ({{template header $title}} or even {{template header "index"}}), but that will prevent you passing in anything else to that template.
no, it's impossible parse variable through to another file.
according to this:
A variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation.
Is it possible to render multiple html templates with the same name in golang. The reason is, that i want to make a layout and reuse it for multiple views. For example:
{{define "MainLayout"}}
<html>
<head>
<title>{{.Title}}</title>
</head>
<body>
<div>{{template "Content" .}}</div>
</body>
</html>
{{end}}
Content could be different templates, that all are defined by {{define "Content"}}
I believe elithrar has what you are looking for, but unfortunately it's not currently supported. The typical way of handling this problem would be defining your header and footer in their own templates and doing the inverse of your approach. And you can pass the struct being given to the template parser into those templates to render your pages.
{{define "header"}}
<html>...
{{end}}
{{define "footer"}}
...</html>
{{end}}
{{define "Content"}}
{{template "header" .}}
HTML
{{template "footer" .}}
{{end}}
How are you parsing your templates? You can't have two templates with the same name in the same template tree. However, you could create a custom parsing function that will only add one template named "Content" to your template tree.
Example: https://play.golang.org/p/35X3i_jPzS
I am trying to put values into a "header" template, like the title and navigation links but can't access the variables that I sent to the main template from the included one.
Rendering the template:
...
templateName := "index"
args := map[string]string{
"Title": "Main Page",
"Body": "This is the content",
}
PageTemplates.ExecuteTemplate(w, templateName+".html", args)
...
index.html template:
{{template "header"}} <-- Including the "header.html" template
{{.Body}} <-- Variable that works
{{template "footer"}} <-- Does not matter!
header.html template:
{{define "header"}}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.Title}}</title> <-- Variable empty :(
</head>
<body>
{{end}}
Apparently, it won't work that way.
Maybe there's a way I could parse/get the template and put my variables into it without putting the whole header file into code? Then I could just send that template as a variable to my main template. But that does not seem like it would be the best way to do it.
You can pass the context to the template when you call it. In your example, changing {{template "header"}} to {{template "header" .}} should be sufficient.
The relevant parts from the official docs:
{{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.
PS: It is not relevant to the question, but you should also remove the newline between {{define "header"}} and <!DOCTYPE html>, so that the doctype is really the first thing in your template.
I have a file test.md:
---
layout: test
item: {"label":"value"}
---
This text should not appear
and a corresponding file _layouts/test.html:
<!DOCTYPE html>
<html>
<body>
<h1>Hello world!</h1>
The field <em>label</em> has value <em>{{ page.item.label }}</em>.
</body>
</html>
On my local server I get, as expected, the following page in _site/test.html:
<!DOCTYPE html>
<html>
<body>
<h1>Hello world!</h1>
The field <em>label</em> has value <em>value</em>.
</body>
</html>
while on github (see http://altomani.github.com/test.html) the result is:
<p>This text should not appear</p>
Though I couldn’t reproduce the problem, I would suggest you to follow the guidelines and use yaml in preambles rather than dicts:
---
layout : test
item :
label : value
---
This should definitely work.