I'm trying to generate a web page in Go lang. I'm currently using the Goji framework ( http://goji.io ) and I want to generate all of the heads and parts of the body of the web-page, but then I want some of the content to be written based on results from the code.
For example as in PHP, one can write HTML, js, or CSS and then in the PHP tags, write the code which is interpreted there.
How can I write my html, css, and js and then have Golang code within it that is complied and executed as the page is rendered?
As mentioned in issue 13, use Go html/template package.
i.e.
// Shorthand
type M map[string]interface{}
func viewHandler(c web.C, w http.ResponseWriter, r *http.Request) {
title := c.URLParams["title"]
p, err := loadPage(title)
if err != nil {
...
}
// do other things
template.ExecuteTemplate(w, "results.html", M{
"title": title,
"results": results,
"pagination": true,
}
}
results.html
{{range .Results }}
<h1>{{ Result.Name }}</h1>
<p>{{ Result.Body }}</p>
{{ end }}
Using a template is also recommended in zenazn/goji/example/main.go.
elithrar also references in the comments the "Writing Web Applications article, section The html/template package" for more.
Related
I need to create an html page that display all the "forums" present in the database in my .html file.
Example:
<body>
{{with index . 0}}
{{.Name}}<br>{{.Descr}}</td>
{{end}}
{{with index . 1}}
{{.Name}}<br>{{.Descr}}
{{end}}
</body>
func index(w http.ResponseWriter, r *http.Request) {
forums := GetForumsFromDB() // return a slice of type Forum from the db
tpl.ExecuteTemplate(w, "index.html", forums)
}
type Forum struct {
Id int
Name string
Descr string
}
But in this case I need to already know how many forums are there in the db when writing the .html file. How should I approach this? Should I pass the html into the template together with my slice? Should I use a method of Forum that return the html for every forum?
Use range:
{{range .}}
{{.Name}}<br>{{.Descr}}
{{end}}
I have an if else block in my template. when else if is true it is rendered always empty as if else or else if is not there
here is my template
in this case, it renders nothing
And also I am using text/template because html/template send the page completely empty
//the template
<script>
{{if.PassChange}}
swal("{{.Lang.Success}}", "{{.Lang.PleaseLogin}}", "success")
{{end}}
{{if.UserExists}}
swal("{{.Lang.Fail}}", "{{.Lang.AlreadyMember}}", "error")
{{end}}
</script>
//rendering part
BasePath.Get("/", func(w http.ResponseWriter, r *http.Request) {
tpl.ExecResponse(w, struct{Lang map[string]string ; UserExists bool}{Lang:lang.GetLang(r),UserExists:true})
})
If you print the error from executing the template, you will find that the template cannot evaluate the field PassChange. One possible fix is to add a PassChange field to the struct.
tpl.ExecResponse(w, struct{PassChange bool; Lang map[string]string ; UserExists bool}{Lang:lang.GetLang(r),UserExists:true})
I'm looking to see if there is a better (faster, more organised) way to split up my templates in Go. I strongly prefer to stick to html/template (or a wrapper thereof) since I trust its security model.
Right now I use template.ParseGlob to parse all of my template files in within init().
I apply template.Funcs to the resulting templates
I set a $title in each template (i.e. listing_payment.tmpl) and pass this to the content template.
I understand that html/template caches templates in memory once parsed
My handlers only call t.ExecuteTemplate(w, "name.tmpl", map[string]interface{}) and don't do any silly parsing on each request.
I compose templates from multiple pieces (and this is the bit I find clunky) as below:
{{ $title := "Page Title" }}
{{ template "head" $title }}
{{ template "checkout" }}
{{ template "top" }}
{{ template "sidebar_details" . }}
{{ template "sidebar_payments" }}
{{ template "sidebar_bottom" }}
<div class="bordered-content">
...
{{ template "listing_content" . }}
...
</div>
{{ template "footer"}}
{{ template "bottom" }}
My three questions are:
Is this performant, or do the multiple {{ template "name" }} tags result in a potential per-request performance hit? I see a lot of write - broken pipe errors when stress testing heavier pages. This might just be due to socket timeouts (i.e. socket closing before the writer can finish) rather than some kind of per-request composition, though (correct me if otherwise!)
Is there a better way to do this within the constraints of the html/template package? The first example in Django's template docs approaches what I'd like. Extend a base layout and replace the title, sidebar and content blocks as needed.
Somewhat tangential: when template.ExecuteTemplate returns an error during a request, is there an idiomatic way to handle it? If I pass the writer to an error handler I end up with soup on the page (because it just continues writing), but a re-direct doesn't seem like idiomatic HTTP.
With some help on Reddit I managed to work out a fairly sensible (and performant) approach to this that allows:
Building layouts with content blocks
Creating templates that effectively "extend" these layouts
Filling in blocks (scripts, sidebars, etc.) with other templates
base.tmpl
<html>
<head>
{{ template "title" .}}
</head>
<body>
{{ template "scripts" . }}
{{ template "sidebar" . }}
{{ template "content" . }}
<footer>
...
</footer>
</body>
index.tmpl
{{ define "title"}}<title>Index Page</title>{{ end }}
// We must define every block in the base layout.
{{ define "scripts" }} {{ end }}
{{ define "sidebar" }}
// We have a two part sidebar that changes depending on the page
{{ template "sidebar_index" }}
{{ template "sidebar_base" }}
{{ end }}
{{ define "content" }}
{{ template "listings_table" . }}
{{ end }}
... and our Go code, which leverages the map[string]*template.Template approach outlined in this SO answer:
var templates map[string]*template.Template
var ErrTemplateDoesNotExist = errors.New("The template does not exist.")
// Load templates on program initialisation
func init() {
if templates == nil {
templates = make(map[string]*template.Template)
}
templates["index.html"] = template.Must(template.ParseFiles("index.tmpl", "sidebar_index.tmpl", "sidebar_base.tmpl", "listings_table.tmpl", "base.tmpl"))
...
}
// renderTemplate is a wrapper around template.ExecuteTemplate.
func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
// Ensure the template exists in the map.
tmpl, ok := templates[name]
if !ok {
return ErrTemplateDoesNotExist
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
tmpl.ExecuteTemplate(w, "base", data)
return nil
}
From initial benchmarks (using wrk) it seems to be a fair bit more performant when it comes to heavy load, likely due to the fact that we're not passing around a whole ParseGlob worth of templates every request. It also makes authoring the templates themselves a lot simpler.
Before I being a bit of background, I am very new to go programming language. I am running go on Win 7, latest go package installer for windows. I'm not good at coding but I do like some challenge of learning a new language. I wanted to start learn Erlang but found go very interesting based on the GO I/O videos in youtube.
I'm having problem with capturing POST form values in GO. I spend three hours yesterday to get go to print a POST form value in the browser and failed miserably. I don't know what I'm doing wrong, can anyone point me to the right direction? I can easily do this in another language like C#, PHP, VB, ASP, Rails etc. I have search the entire interweb and haven't found a working sample. Below is my sample code.
Here is Index.html page
{{ define "title" }}Homepage{{ end }}
{{ define "content" }}
<h1>My Homepage</h1>
<p>Hello, and welcome to my homepage!</p>
<form method="POST" action="/">
<p> Enter your name : <input type="text" name="username"> </P>
<p> <button>Go</button>
</form>
<br /><br />
{{ end }}
Here is the base page
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ template "title" . }}</title>
</head>
<body>
<section id="contents">
{{ template "content" . }}
</section>
<footer id="footer">
My homepage 2012 copy
</footer>
</body>
</html>
now some go code
package main
import (
"fmt"
"http"
"strings"
"html/template"
)
var index = template.Must(template.ParseFiles(
"templates/_base.html",
"templates/index.html",
))
func GeneralHandler(w http.ResponseWriter, r *http.Request) {
index.Execute(w, nil)
if r.Method == "POST" {
a := r.FormValue("username")
fmt.Fprintf(w, "hi %s!",a); //<-- this variable does not rendered in the browser!!!
}
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
remPartOfURL := r.URL.Path[len("/hello/"):]
fmt.Fprintf(w, "Hello %s!", remPartOfURL)
}
func main() {
http.HandleFunc("/", GeneralHandler)
http.HandleFunc("/hello/", helloHandler)
http.ListenAndServe("localhost:81", nil)
}
Thanks!
PS: Very tedious to add four space before every line of code in stackoverflow especially when you are copy pasting. Didn't find it very user friendly or is there an easier way?
Writing to the ResponseWriter (by calling Execute) before reading the value from the request is clearing it out.
You can see this in action if you use this request handler:
func GeneralHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method)
fmt.Println(r.URL)
fmt.Println("before",r.FormValue("username"))
index.Execute(w, nil)
if r.Method == "POST" {
fmt.Println("after",r.FormValue("username"))
}
}
This will print out before and after. However, in this case:
func GeneralHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method)
fmt.Println(r.URL)
index.Execute(w, nil)
if r.Method == "POST" {
fmt.Println("after",r.FormValue("username"))
}
}
The after value will be blank.
According to the documentation for html/template the second argument to Execute should be the data you want to put in the template.
Add a {{.}} somewhere in your template and then pass the string you want printed in as the second argument. It should get rendered as part of the template.
For example.go, I have
package main
import "html/template"
import "net/http"
func handler(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("header.html", "footer.html")
t.Execute(w, map[string] string {"Title": "My title", "Body": "Hi this is my body"})
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
In header.html:
Title is {{.Title}}
In footer.html:
Body is {{.Body}}
When going to http://localhost:8080/, I only see "Title is My title", and not the second file, footer.html. How can I load multiple files with template.ParseFiles? What's the most efficient way to do this?
Thanks in advance.
Only the first file is used as the main template. The other template files need to be included from the first like so:
Title is {{.Title}}
{{template "footer.html" .}}
The dot after "footer.html" passes the data from Execute through to the footer template -- the value passed becomes . in the included template.
There is a little shortcoming in user634175's method: the {{template "footer.html" .}} in the first template must be hard coded, which makes it difficult to change footer.html to another footer.
And here is a little improvement.
header.html:
Title is {{.Title}}
{{template "footer" .}}
footer.html:
{{define "footer"}}Body is {{.Body}}{{end}}
So that footer.html can be changed to any file that defines "footer", to make different pages