Placeholders are not replaced - go

I am experimenting with the package http/template.
I have also already managed that e.g. the header, footer, navbar and so on were included in the base template:
{{ define "base" }}
<!DOCTYPE html>
<html lang="en">
<!-- Start Head -->
<head>
{{ template "head" }}
</head>
<!-- End Head -->
<!-- Start Body -->
<body>
{{ template "navbar" }}
{{ template "content" }}
{{ template "footer" }}
</body>
<!-- End Body -->
</html>
{{ end }}
404 page:
{{ define "content" }}
[...]
<h1 class="text-light text-right">404</h1>
<small>{{.CurrentURL}}</small>
[...]
{{ end }}
So here the variable CurrentURL should be replaced by the current URL.
However, this is only displayed empty ("") on the website:
<small></small>
But now I want to replace a variable, which is displayed on the web page only as "".
Go Code:
Parser:
func (parser *TemplateParser) ParseTemplate(name string) (tpl *template.Template, err error) {
root, err := template.New("root").Parse(rootTmpl)
// ...
return root.ParseFiles(files...)
}
Route:
func (ws *WebServer) Exec(name string, r *http.Request, w http.ResponseWriter, data map[string]interface{}) (err error) {
// ...
// add default data
data["CurrentURL"] = r.URL.RequestURI()
// ...
return tpl.Execute(w, data)
}
Even with an array, I can't use range etc:
type Test struct {
CurrentURL string
C []string
}
t := Test{
CurrentURL: "Current URL",
C: []string {"C1", "c2", "ccc4"},
}
tpl.Execute(w, t)
<ul>
{{range .C}}
<li>{{.}}</li>
{{end}}
</ul>
<!-- No <li></li> is created -->
What am I doing wrong?

You have to pass the context to the instantiated templates. Use
{{ template "content" .}}
to pass the data in . to the content template.

You're not passing any data to the child templates. Per the 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.

Related

Use the same template with different param/variables in 1 page

I am using Go gin gonic for my web app. How do I use the same template file multiple times in 1 page with different variables passed to the template.
segment.tmpl
{{ define "segment" }}
<div>{{ .Variable }}</div>
{{ end }}
layout.tmpl
<!DOCTYPE HTML>
<html>
<body>
{{ template "segment . }} #with a variable 1
{{ template "segment . }} #with different variable
{{ template "segment . }} #another same template with another
</body>
</html>
main.go
r.GET("/home/", func(c *gin.Context) {
tmpl := template.Must(template.ParseFiles("templates/layout.tmpl", "templates/product_add.tmpl", "templates/segment.tmpl")
r.SetHTMLTemplate(tmpl)
c.HTML(200, "layout", gin.H {
"Variable1": "var1",
"variable2": "var2",
})
}
How do I use segment.tmpl multiple times in the page "home" and passing different kind of variables to the segment.tmpl?
I have searched everywhere and have found nothing, the closest thing is template.Clone, but still couldn't find any examples of it.
You can pass any value as the "pipeline" to the template, it doesn't have to be the "dot", i.e. you could pass the result of a function call, or, in this case, the result of accessing a map's value.
{{ template "segment" .Variable1 }}
and then inside the template "segment" you can refer to the pipeline using the dot, i.e. {{ . }}.
segment.tmpl
{{ define "segment" }}
<div>{{ . }}</div>
{{ end }}
layout.tmpl
<!DOCTYPE HTML>
<html>
<body>
{{ template "segment .Variable1 }}
{{ template "segment .Variable2 }}
{{ template "segment .AnotherVariable }}
</body>
</html>

How to set web template variable to a dynamic html&golang code?

I have two web page on golang and I want to embed this pages codes to {{.content}} variable (defined in templates/main.html) being with dynamic according to the coming requests.
For example if the guest enter the userregister page I want to the {{.content}} variable will be userregister codes otherwise userprofile codes.
templates/userregister.html page codes;
{{ define "userregister" }}
...
{{.specialmessage}}
...
{{ end }}
templates/userprofile.html page codes;
{{ define "userprofile" }}
...
{{.specialmessage}}
...
{{ end }}
templates/main.html;
{{ define "main" }}
<!DOCTYPE html>
<html lang="tr">
{{ template "head" . }}
<body>
<div class="container-fluid">
{{ template "header" . }}
<div class="row">
<nav class="col-12 col-md-2 p-0">
{{ template "leftmenu" . }}
</nav>
<div class="container-fluid col-12 col-md-10">
{{.content}}
</div>
</div>
{{ template "footer" . }}
</div>
</body>
</html>
{{ end }}
The userregister page controller;
func PgUserRegister(c *gin.Context) {
c.HTML(http.StatusOK,"main", gin.H{
"pgETitle": "User Register page",
"specialmessage": "You are on the userregister page.",
"content": template.ParseFiles("userregister.html"),
})
}
The userprofile page controller;
func PgUserProfile(c *gin.Context) {
c.HTML(http.StatusOK,"main", gin.H{
"pgETitle": "User Profile",
"specialmessage": "You are on the userprofile page.",
"content": template.ParseFiles("userprofile.html"),
})
}
Parse all templates when starting the router.
router.LoadHTMLFiles("templates/main.html", "templates/userregister.html", "templates/userprofile.html")
Then in your handler add to the gin.H{ ... } expression a boolean variable, e.g. "isLoggedIn", and then in your main template use an if-else action together with the template action.
{{ if .isLoggedIn }}
{{ template "userprofile" . }}
{{ else }}
{{ template "userregister" . }}
{{ end }}

Golang tmpl HTML text is being interpreted as plain text instead of using the HTML

I have some data given to my template using Go that contains html tags. When I try to display this data, it displays the full text literally, including the HTML tags. Here's the code:
In my .tmpl, I am looping through an object called .SimRpms whose {{ $value }} has html in it like <br>:
{{ range $key, $value := .SimRpms }}
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">{{ $key }}</div>
<div class="panel-body">{{ $value }}</div>
</div>
</div>
{{ end }}
However when I look at the rendered page, the {{ $value }} is rendered as plain text instead of html:
How can I get {{ $value }} to interpret the text as HTML?
Here's what it looks like in the JS Console:
I know this is similar to this question: Golang html output is being interpreted as plain text instead of being received as html however the rest of the page is displaying HTML ok and the content type of the entire page has been set already, but this little panel isn't displaying the HTML (it's displaying it literally).
package main
import (
"html/template"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", SayHello)
log.Fatal(http.ListenAndServe(":2332", nil))
}
func SayHello(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseGlob("hello.gtml")
if err != nil {
panic(err)
}
t.Execute(w, map[string]template.HTML{"name": template.HTML("<a>Katie Sissons</a>")})
return
}
works with the template
hello.gtml below.
<html>
<head></head>
<body>{{ .name }}</body>
</html>
html/template package treats template.HTML as a type and applies escape to normal strings. If you want your string to go without escape, this type can do that for you.
What I ended up doing to get this to work was manipulating the data that I am displaying. Instead of using map[string]string for SimRpms, I used map[string][]string so that i can iterate through the string slice and insert a <br> between them:
{{ range $key, $value := .SimRpms }}
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">{{ $key }}</div>
<div class="panel-body">
{{ range $keytwo, $valuetwo := $value }}
{{ $valuetwo }}<br>
{{ end }}
</div>
</div>
</div>
{{ end }}

Execute template fragment in main template based on requested URL

Not sure how to name this correctly.
Is there any way to write one main template and many fragments and inject required fragment based on URL user requests.
Let's say i have /customers/profile and /customers/projects. I want to write one main customer.html template file and one customer-includes.html file with 2 {{ define "profile" }} and {{ define "projects" }} fragments.
Then i want have 2 handlers to handle /customers/profile and /customers/projects and to execute customer.html template.
But, when user go to the URL /customers/profile i want to inject in main template {{ template "profile" . }} and if he goes to /customers/projects i want to inject {{ template "projects" . }}.
What is the best way to do this?
I assume i need to use some kind of {{ if / else }} there. As example below. But mby there is better way.
{{ if ( eq .Section "customer-profile") }} // Could be replaced with Page ID
{{ template "profile" . }}
{{ else }}
{{ template "projects" . }}
{{ end}}
You may use template blocks for this.
templates/customers-base.html:
<html>
<head>
<title>{{.title}}</title>
<link rel="stylesheet" type="text/css" href="static/styles.css">
<!-- You can include common scripts and stylesheets in the base template -->
</head>
<body>
{{block "BODY" .}}
{{end}}
</body>
</html>
templates/customers-projects.html:
{{define "BODY"}}
<h1>Your Projects</h1>
<p>Normal template goes here</p>
<p>{{.myvar}}<p>
{{end}}
You can copy this format for templates/customers-profile.html.
Your project code:
data := map[string]interface{}{
"title": "Base template example",
"myvar": "Variable example",
}
layoutCustomersBase := template.Must(template.ParseFiles("templates/customers-base.html"))
layoutCustomersProjects := template.Must(layoutCustomersBase.ParseFiles("templates/customers-projects.html"))
// Or layoutCustomersProfile, if you are parsing in the '/customers/profile' handler.
err := layoutError.Execute(w, data)
Notice that you can define the "title" variable when you execute the customers-projects template; it will be used in the base template.

access my array of structs in my template

I'm passing an array of structs to my template, the data is there but I can't find a way to access specific data, I tried many things already, here it is
My Struct
type Data struct {
Destination string
IData interface{}
}
then in my controller I have
users := []models.User {}
userRow := models.User{Name: "jon", Email: "jon#mail.com"}
users = append(users, userRow)
users2 := users
data := models.Data{
Destination: "content",
IData: users,
}
data2 := models.Data{
Destination: "content",
IData: users2,
}
dataFinal := []models.Data{}
dataFinal = append(dataFinal, data)
dataFinal = append(dataFinal, data2)
and this is my template, though this didn't seem to work, it does show the raw data but can't seem to access the name specifically.
{{define "content"}}
<h2>THIS IS THE BODY CONTENT</h2>
<ul>
{{.}}
{{range .}}
<li>{{.}}</li>
{{end}}
</ul>
{{end}}
edit:
project: https://github.com/og2/go-og2-mvc
you may wanna run:
go get github.com/go-sql-driver/mysql
go get github.com/julienschmidt/httprouter
for it to work and should be just fine!
If the pipeline value that you pass to the "content" template execution is dataFinal, then you have to use two {{range}} actions as dataFinal itself is a slice (of type []models.Data), and Data.IData is also a slice (of type []model.User).
Inside the inner {{range}} you may refer to the User.Name like .Name:
<li>{{.Name}}</li>
See this working example:
const templ = `{{define "content"}}
<h2>THIS IS THE BODY CONTENT</h2>
<ul>
{{.}}
{{range .}}
<ul>
{{range .IData}}
<li>{{.Name}}</li>
{{end}}
</ul>
{{end}}
</ul>
{{end}}`
// Parsing and executing the template:
t := template.Must(template.New("").Parse(templ))
fmt.Println(t.ExecuteTemplate(os.Stdout, "content", dataFinal))
Output (try it on the Go Playground):
<h2>THIS IS THE BODY CONTENT</h2>
<ul>
[{content [{jon jon#mail.com}]} {content [{jon jon#mail.com}]}]
<ul>
<li>jon</li>
</ul>
<ul>
<li>jon</li>
</ul>
</ul>
<nil>

Resources