I've the below code:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"onsen/resources"
)
var view *template.Template
var err error
func init() {
fmt.Println("Starting up.")
view = template.Must(template.ParseFS(resources.Views, "templates/layouts/*.html", "templates/views/*.html", "templates/partials/*.html"))
if err != nil {
log.Fatal("Error loading templates:" + err.Error())
}
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8070",
}
http.Handle("/webUI/", http.StripPrefix("/webUI/", http.FileServer(http.FS(resources.WebUI))))
http.HandleFunc("/process", process)
http.HandleFunc("/home", home)
http.HandleFunc("/test", test)
server.ListenAndServe()
}
Where onsen/resources is:
package resources
import (
"embed"
)
// Views is our static web server layouts, views with dynamic content and partials content that is a static view.
//go:embed templates/layouts templates/views templates/partials
var Views embed.FS
And the routes functions are:
package main
import (
"log"
"net/http"
)
func home(w http.ResponseWriter, r *http.Request) {
err = view.ExecuteTemplate(w, "home.html", nil)
if err != nil {
log.Fatalln(err)
}
}
func test(w http.ResponseWriter, r *http.Request) {
err = view.ExecuteTemplate(w, "test.html", nil)
if err != nil {
log.Fatalln(err)
}
}
func process(w http.ResponseWriter, r *http.Request) {
err = view.ExecuteTemplate(w, "process.html", nil)
if err != nil {
log.Fatalln(err)
}
}
My templates are:
base.html
<!-- Content of base.html: -->
{{define "base"}}
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="utf-8">
</head>
<body>
{{template "content" .}}
</body>
</html>
{{end}}
And the views are:
<!-- Content of home.html: -->
{{template "base" .}}
{{define "content"}}
This is home
{{end}}
And;
<!-- Content of test.html: -->
{{template "base" .}}
{{define "content"}}
test file is here
{{end}}
And
<!-- Content of process.html: -->
{{template "base" .}}
{{define "content"}}
process goes here
{{end}}
But ALL the routes are showing the same result, which is same as template test.html
I referred to this for my template structure, but looks something related to embed!
Thanks to the comment by Cerise
The application parses all of the template files to one template set.
The "content" template in test.html is the last "content" template to
be added to the set. That's the one you see for each page. Parse the
template for each page to a separate set.
So, here the correct working code
package main
import (
"html/template"
"log"
"net/http"
"onsen/resources"
)
func process(w http.ResponseWriter, r *http.Request) {
view := template.Must(template.ParseFS(resources.Views, "templates/layouts/base.html", "templates/views/other.html", "templates/partials/*.html"))
type approval struct {
Status bool
}
workflow := approval{Status: false}
err = view.ExecuteTemplate(w, "process.html", workflow)
if err != nil {
log.Fatalln(err)
}
}
And template process.html is:
<!-- Content of other.html: -->
{{template "base" .}}
{{define "content"}}
process goes here
{{ .Status }}
{{if .Status}}
{{template "approved"}}
{{else}}
{{template "rejected"}}
{{end}}
{{end}}
Related
I wrote code in golango to connect to the database on the server and output the contents of the tables to the website. I also wrote code for the html output of the table. There are no problems and it connects, but the error "404 page not found" lights up on the web page. What is this error and what is the reason? This is the first time I've seen this
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"html/template"
_ "log"
"net/http"
)
type Жанр struct {
idЖанр int
Название_жанра string
}
var database *sql.DB
func home_db(w http.ResponseWriter, r *http.Request) {
rows, err := database.Query("select * from newbd.Жанр")
if err != nil {
panic(err)
}
defer rows.Close()
ganr := []Жанр{}
for rows.Next() {
p := Жанр{}
err = rows.Scan(&p.idЖанр, &p.Название_жанра)
if err != nil {
panic(err)
continue
}
ganr = append(ganr, p)
}
tmpl, _ := template.ParseFiles("home.html")
tmpl.Execute(w, ganr)
}
func main() {
db, err := sql.Open("mysql", "xxxxx:xxxxxx#tcp(xx.xx.xxx.xxx:xx)/xxxxx")
if err != nil {
panic(err)
}
defer db.Close()
fmt.Println("OK")
http.HandleFunc("/dat/", home_db)
http.ListenAndServe(":8100", nil)
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RUMP</title>
</head>
<body>
<table>
<thead>
<th>idЖанр</th>
<th>Название_жанра</th>
</thead>
{{range . }}
<li>
<td>{{.idЖанр}}</td>
<td>{{.Название_жанра}}</td>
</li>
{{.end}}
</table>
</body>
</html>
I am building a website using Golang templates and needed to display some text in the footer template. It's a variable that resolves in header.html and index.html.
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
type Data struct {
Title string
Field1 string
Field2 template.HTML
FooterField string
}
var tmpl *template.Template
func main() {
router := mux.NewRouter()
port := ":8085"
data := Data{}
data.Title = "Title"
data.FooterField = "This text does not appear in the footer template"
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "index", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var err error
tmpl, err = template.ParseGlob("views/*")
if err != nil {
panic(err.Error())
}
router.PathPrefix("/").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir("./static/")).ServeHTTP(res, req)
})
fmt.Println("Server running on localhost" + port)
err = http.ListenAndServe(port, handlers.CompressHandler(router))
if err != nil {
log.Fatal(err)
}
}
And in the ./views I have header.html
{{define "header"}}<!doctype html><html lang="en"><head><meta charset="utf-8"><title>{{.Title}}</title></head><body><h1>Header template</h1><div>{{.FooterField}}</div>{{end}}
index.html
{{define "index"}}{{template "header" . }}
<h1>Index template</h1>
<div>{{.FooterField}}</div>
{{template "footer"}}{{end}}
footer.html
{{define "footer"}}<h1>Footer template</h1>
Missing FooterField->{{.FooterField}}</body></html>{{end}}
And finally the output in the browser on http://localhost:8085/
Header template
This text does not appear in the footer template
Index template
This text does not appear in the footer template
Footer template
Missing FooterField->
This code should be able to be reproduced simply by copying and pasting.
Any clue to what my issue is?
you are not passing anything to the footer template. But you pass . to the header template, so you see the value of .FooterField only there.
In index.html change it to: {{template "footer" . }}
Guys I am making a create your own adventure type book in which the user has options to select events. I am taking the story data from a json file. I have created two files named story.go and main.go where story.go handles all the functions and main.go has only the server. Look at the following codes
story.go
package gyg
import (
"encoding/json"
"io"
"net/http"
"text/template"
)
var defaultHandlerTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Give Yourself Goosebumps</title>
</head>
<body>
<h1>{{.Title}}</h1>
{{range .Paragraphs}}
<p>{{.}}</p>
{{end}}
<ul>
{{range .Options}}
<li> {{.Text}} </li>
{{end}}
</ul>
</body>
</html>
`
var tpl *template.Template
type Story map[string]Chapter
type Chapter struct {
Title string `json:"title"`
Paragraphs []string `json:"story"`
Options []Option `json:"options"`
}
type Option struct {
Text string `json:"text"`
Arc string `json:"arc"`
}
type handler struct {
s Story
}
func init() {
tpl = template.Must(template.New("").Parse("defaultHandlerTemplate"))
}
func JsonStory(r io.Reader) (Story, error) {
d := json.NewDecoder(r)
var story Story
if err := d.Decode(&story); err != nil {
return nil, err
}
return story, nil
}
func NewHandler(s Story) http.Handler {
return handler{s}
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := tpl.Execute(w, h.s["intro"])
if err != nil {
panic(err)
}
}
main.go
package main
import (
"flag"
"fmt"
"go-projects/gyg"
"log"
"net/http"
"os"
)
func main() {
filename := flag.String("file", "gopher.json", "the file with GYG story.")
flag.Parse()
f, err := os.Open(*filename)
if err != nil {
panic(err)
}
story, err := gyg.JsonStory(f)
if err != nil {
panic(err)
}
server := http.Server{
Addr: "127.0.0.1:3000",
}
h := gyg.NewHandler(story)
fmt.Printf("Startin the server on port %s\n", server.Addr)
log.Fatal(http.ListenAndServe(server.Addr, h))
}
On running main.go the server is listening on port 3000 but when opening port 3000 on browser, it's displaying
defaultHandlerTemplate
I have a simple webserver and I want to open imagesin browser. The problem is browser can't open an image I sent.
package main
import (
"io/ioutil"
"net/http"
"io"
"html/template"
"fmt"
)
func main() {
http.HandleFunc("/images", images)
http.ListenAndServe(":8080", nil)
}
func images(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseFiles("templates/link.html")
if err != nil {
fmt.Fprintf(w, err.Error())
return
}
t.ExecuteTemplate(w, "link", nil)
}
Also my html template package, where I create a link to file on my computer. Called link.html
{{ define "link" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> apple</p>
<br>
</body>
</html>
{{ end }}
I do not understand why it doesn't work. Will be very glad for help. In addition all files I wanted to add to server are lying in this golang project
It's because you do not have any dedicated route that handles requests for any images.
My recommendation would be to initialize an HTTP handler that serves file based on the URI pathname. You can use that handler as a way to serve images.
fs := http.FileServer(http.Dir("images"))
And then to bind it:
http.Handle("/images/", http.StripPrefix("/images/", fs))
Here's your full code with my suggestions:
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
// We're creating a file handler, here.
fs := http.FileServer(http.Dir("images"))
http.HandleFunc("/images", images)
// We're binding the handler to the `/images` route, here.
http.Handle("/images/", http.StripPrefix("/images/", fs))
http.ListenAndServe(":8080", nil)
}
func images(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseFiles("templates/link.html")
if err != nil {
fmt.Fprintf(w, err.Error())
return
}
t.ExecuteTemplate(w, "link", nil)
}
I need to render templates into different kinds of layout. Here's my directory structure.
myapp
|
│ main.go
│
├───static
│ script.js
│ style.css
│
└───templates
│ page1.tmpl
│ page2.tmpl
│ page3.tmpl
│ page4.tmpl
│ page5.tmpl
│
└───layouts
base1.tmpl
base2.tmpl
base3.tmpl
I have done rendering templates to a single layout template but, I can't make it work on multiple layouts. Here's what I got so far:
package main
import (
"html/template"
"net/http"
"fmt"
"github.com/urfave/negroni"
"github.com/oxtoacart/bpool"
"path/filepath"
"log"
)
var (
templates map[string]*template.Template
bufpool *bpool.BufferPool
)
func main() {
loadTemplates()
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
renderTemplate(w, "page1.tmpl",nil)
})
n := negroni.New()
n.Use(negroni.NewLogger())
n.UseHandler(mux)
http.ListenAndServe(":8080", n)
}
func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
tmpl, ok := templates[name]
if !ok {
return fmt.Errorf("The template %s does not exist.", name)
}
buf := bufpool.Get()
defer bufpool.Put(buf)
err := tmpl.ExecuteTemplate(buf, "base1.tmpl", data)
if err != nil {
return err
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
buf.WriteTo(w)
return nil
}
func loadTemplates() {
if templates == nil {
templates = make(map[string]*template.Template)
}
tmplDir := "templates/"
layouts, err := filepath.Glob(tmplDir + "layouts/*.tmpl")
if err != nil {
log.Fatal(err)
}
includes, err := filepath.Glob(tmplDir + "*.tmpl")
if err != nil {
log.Fatal(err)
}
for _, include := range includes {
files := append(layouts, include)
templates[filepath.Base(include)] = template.Must(template.ParseFiles(files...))
}
fmt.Print(includes)
bufpool = bpool.NewBufferPool(64)
}
Here's how base1.tmpl looks like:
{{define "base1"}}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{block "title" .}}{{end}}</title>
</head>
<body>
{{template "content" .}}
</body>
</html>
{{end}}
And here's how page1.tmpl looks like:
{{define "title"}}Page 1{{end}}
{{define "content"}}
<p>Page 1 contents</p>
{{end}}
I normally take the approach of rendering twice, once for content, once for layout, this lets you use any content in any layout and defer that decision till runtime. Would be interested in other approaches if other people do it differently, but this is working for me at present.
So using the code you have posted, something like this in handler:
data := map[string]interface{}{
"title": "hello world",
}
renderTemplate(w, "base1.tmpl", "page1.tmpl", data)
...
in renderTemplate pass in a layout as well as a template and:
// Render the template 'name' with data
buf := bufpool.Get()
err := tmpl.ExecuteTemplate(buf, name, data)
if err != nil {
return err
}
// Set the content as a key on data (set as html as it is rendered)
data["content"] = template.HTML(buf.Bytes())
bufpool.Put(buf)
// Render the layout 'layout' with data, using template as content key
buf = bufpool.Get()
defer bufpool.Put(buf)
err = tmpl.ExecuteTemplate(buf, layout, data)
if err != nil {
return err
}
Layout:
<html>
<body>
<h1>Base 1</h1>
{{.content}}
</body>
</html>
Page:
<h2>{{.title}}</h2>
<h3>Page 1</h3>
Here is a link to full code:
https://play.golang.org/p/R2vr4keZec