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>
Related
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.
I have a struct of type Item that contains ItemFields which is a slice of type string. I would like to conditionally print each string in ItemFields that is a hyperlink with an anchor tag. To do so, I am using a function, IsHyperlink, to check whether each string in the slice should be wrapped in an anchor tag or simply printed out.
type Item struct {
ItemFields []string
}
I am looping through ItemFields in my page.html like this.
{{range .Items}}
<ul>
<li>
{{range .ItemFields}}
{{if .IsHyperlink .}}
{{.}}
{{else}}
{{.}}
{{end}}
{{end}}
</li>
</ul>
{{end}}
However, when I run the application IsHyperlink is reporting that it 'cant evaluate field IsHyperlink in type string.
How can I change my go code to successfully wrap the hyperlinks in anchor tags?
The value . in that context is a string, not the Item. Use a variable to refer to the item:
{{range $item := .Items}}
<tr>
<td>
{{range .ItemFields}}
{{if $item.IsHyperlink .}}
{{.}}
{{else}}
{{.}}
{{end}}
{{end}}
</td>
</tr>
{{end}}
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 }}
I am having below JSON structure.
func getJsonMappings() *string {
data := `{
"CategoryGroup": {
"Category subgrp1": ["type1", "type2"],
},
"CategoryGroupDetail" : {
"type1":{
"extension":"abc",
"title" : "this is description",
"other": "i have some other details apart from above in this map"
},
"type2" :{
"extension":"abc",
"title" : "this is description",
"other": "i have some other details apart from above in this map"
}
}
}`
return &data
}
I am Unmarshalling above JSON to golang data-structure like below in controller function definition
func (this *MainPageController) Get() {
jsonData := getJsonMappings()
var catMapObj map[string]interface{}
err := json.Unmarshal([]byte(*jsonData), &catMapObj)
if err != nil {
panic(err.Error())
}
this.Data["CategoryGroup"] = catMapObj["CategoryGroup"]
this.Data["CatAttributeMapping"] = catMapObj["CatAttributeMapping"]
this.TplName = "index.tpl"
}
and trying to render below template.
<ul class="collapsible collapsible-accordion">
{{ range $eachCategory, $subCategoriesList := .CategoryGroup }}
<li class="bold"><a class="collapsible-header waves-effect waves-teal">{{ $eachCategory }}</a>
<div class="collapsible-body" style="">
<ul>
{{ range $_, $subConvertorCategoryId := $subCategoriesList }}
<li><a id="{{ $subConvertorCategoryId }}" class='doc_cvt' href="#">{{ $subConvertorCategoryId|getCategoryTitle }}</a></li>
{{ end }}
</ul>
</div>
</li>
{{ end }}
</ul>
where getCategoryTitle is template function. But I am not getting any value for type variable as function parameter. My template function definition looks like
func GetCategoryTitle(type string) (title string) {
.....
}
if I hardcode the value of "type" to "type1" inside the function then all looks good. But I want to sent the value from template at run time. At the same moment of time I am able to pass the value of ".CategoryGroup" to template function.
Hence my question is :
1- How to pass key or value of map received while parsing template to golang template function?
2- If you will look above structure closely then you will find that I need not to write the template function. I should get the value like
{{ .CategoryGroupDetail.$subConvertorCategoryId.title }}. But I am not able to do so. I have did the same with django (python framework). There must be way to do the same in golang/beego as well.
I am new to golang and Beego. Please guide me how to proceed further.
Try1:
<ul class="collapsible collapsible-accordion">
{{ range $eachCategory, $subCategoriesList := .CategoryGroup }}
<li class="bold"><a class="collapsible-header waves-effect waves-teal">{{ $eachCategory }}</a>
<div class="collapsible-body" style="">
<ul>
{{ range $_, $subConvertorCategoryId := $subCategoriesList }}
{{ $categoryDetail := index .CatAttributeMapping $subConvertorCategoryId}}
<li><a id="{{ $subConvertorCategoryId }}" class='doc_cvt' href="#">{{ $categoryDetail.title }}</a></li>
{{ end }}
</ul>
</div>
</li>
{{ end }}
I am getting below error at run time -
template: index.tpl:38:32: executing "index.tpl" at <.CatAttributeMapping>: can't evaluate field CatAttributeMapping in type interface {}
It looks like you are trying to access the internals of a map using a dot operator. Not knowing what the final result should look like makes this a little more difficult.
I think this example will get you where you want to go for both questions:
{{ range $eachCategory, $subCategoriesList := .CategoryGroup }}
<li class="bold"><a class="collapsible-header waves-effect waves-teal">{{ $eachCategory }}</a>
<div class="collapsible-body" style="">
<ul>
{{ range $key, $val := index .CatAttributeMapping $eachCategory }}
<li><a id="{{ $key}}" class='doc_cvt' href="#">{{ $val.title }}</a></li>
{{ end }}
</ul>
</div>
</li>
{{ end }}
For more details on the index command check out: http://golang.org/pkg/text/template/
The key part being
index Returns the result of indexing its first argument by the
following arguments. Thus "index x 1 2 3" is, in Go syntax,
x1[2][3]. Each indexed item must be a map, slice, or array.
Beego is just using the golang base template system in most cases.
Edit 1: You are asking a compound question so things get a little tricky. The first thing to figure out is if you are parsing the data correctly into a struct. If you are not doing that go will pass it into an interface for you to figure out how to deal with. From your code it looks like you are dealing with that sort of situation.
So take it one problem at a time. this is a great Q&A that covers parsing nested structures in go
I would encourage you to resubmit your question with different tags if you are still having problems. Submit one to golang json trying to get the parse correct and one to golang templates once you have verified the structs are properly set up.
First get your data into a struct then make it work with a template. I am sorry I do not have a copy paste solution for you but I am a little busy now.
I will do what I can to come back to this question because I don't think that you are alone. Dealing with nested structs with the JSON parser and dealing with the templating engine can be difficult. We need to create more examples of how to do things!
My template looks like this currently:
{{range .Users}}
<div ...>
<div class="row XXXX">
</div>
{{end}}
The XXX has to be replaced with a css-class that is based on a property of the User struct, UserLevel which is a string.
So depending on the value of UserLevel, I will display the correct css class:
UserLevel is "beg" then I need to output "beginner".
UserLevel is "int" then I need to output "intermediate"
etc.
I know I can just rename the css class to match the value of the property, but I don't want to keep a tight coupling between the 2.
Is this possible to do somehow since expressions are not allowed in if statements?
There are several ways to do that, I will cover two. First way is to work with if statements and equality tests in the template:
{{range $count, $user := .Users}}
<div ...>
<div class="row {{if eq $user.UserLevel "beg"}}beginner{{else if eq $user.UserLevel "int" }}intermediate{{else}}default{{end}}">
</div>
{{end}}
The second way is to define a function for the User, which outputs the correct class based on the UserLevel property:
func (u User) CssClass() string {
switch u.UserLevel {
case "beg":
return "beginner"
case "int":
return "intermediate"
default:
return ""
}
}
{{range $count, $user := .Users}}
<div ...>
<div class="row {{$user.CssClass}}">
</div>
{{end}}
I put this little test code in the Go playground, both produce the same output with the correct class.