i going to render html with data,when render,i don't know how to render struct of other file return for render on controller ,
code :
packages controller
type Index struct {
Title string
Body string
}
func IndexController(w http.ResponseWriter , r *http.Request){
if r.Method == "POST"{
data := &Index{
Title: "Hello",
Body: "Welcome to the WebGo.",
}
ff := renders.Sample{Temppath:"templates/index.tmpl",Data:data}
ff.Render(w)
my render package:
package renders
import (
"html/template"
"log"
"net/http"
)
type Sample struct {
Temppath string
Data struct{} ## i don't know how to use pass value of package controller to renders package ?
}
func (obj Sample) Render(w http.ResponseWriter) error {
var indexTemplate = template.Must(template.ParseFiles(obj.Temppath))
if err := indexTemplate.Execute(w, obj.Data); err != nil {
log.Println(err)
return err
}
return nil
}
html code :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="/static/js/sample.js"></script>
<title>{{.Title}}</title>
<style>
body {
font-family: sans-serif;
}
h1 {
background: #ddd;
}
#sidebar {
float: right;
}
</style>
</head>
<body>
<h1>{{.Title}}</h1>
<div id="sidebar">
{{block "sidebar" .}}
<ul>
</ul>
{{end}}
</div>
{{block "content" .}}
<div id="content">
{{.Body}}
</div>
{{end}}
</body>
</html>
how to pass type Index struct to renders package for use indexTemplate.Execute(w, obj.Data)
Declare field Data in struct Sample as interface{}:
type Sample struct {
Temppath string
Data interface{}
}
The type Sample then can also be used in other controllers as placeholder of any data which is going to be passed to template.
Related
I'm having difficulty in rendering the correct content using templates in Go. Either case of navigating to /about or / the same content is getting rendered. Below is the current state of code.
I have read that you can parse templates in each handleFunc (for each request) but that seems to be an inefficient way to mitigate the issue.
Code
I have the following templates
base
header
footer
index
about
{{ define "base"}}
<!DOCTYPE html>
<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.0">
<title>Project Website</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css#2/out/water.css">
</head>
<body>
{{template "header" .}}
{{template "body" .}}
{{template "footer" .}}
</body>
</html>
{{end}}
{{define "header"}}
<h1>Header</h1>
{{end}}
{{define "footer"}}
<h1>Footer</h1>
{{end}}
{{template "base" .}}
{{define "body"}}
<h1>About</h1>
{{end}}
{{template "base" .}}
{{define "body"}}
<h1>Index</h1>
{{end}}
main.go
package main
import (
"html/template"
"log"
"net/http"
)
var tpl *template.Template
func init() {
tpl = template.Must(template.ParseGlob("templates/*"))
}
func main() {
// Connect to database.
// Routes
http.HandleFunc("/about", about)
http.HandleFunc("/", index)
http.HandleFunc("/favicon.ico", doNothing) // TODO Replace with something like do not found
// Listen and serve.
log.Fatal(http.ListenAndServe(":8000", nil))
}
// TODO go away
func doNothing(w http.ResponseWriter, r *http.Request) {}
handlerFunctions.go
package main
import (
"log"
"net/http"
)
func index(rw http.ResponseWriter, req *http.Request) {
log.Println("Index page called")
tpl.ExecuteTemplate(rw, "index.gohtml", nil)
}
func about(rw http.ResponseWriter, req *http.Request) {
log.Println("About page called")
tpl.ExecuteTemplate(rw, "about.gohtml", nil)
}
There are many similar questions implemented in different stacks, but I have not found a useful answer. This code is modeled on many different tutorials, here is one: https://divyanshushekhar.com/golang-forms-data-request-body/
Pressing the button is supposed to submit the form so that the value of dataRequest can be used, however, it does not appear to post. Why?
<!DOCTYPE html>
<meta charset="utf-8" http-equiv="Content-Security-Policy" content="img-src * 'self' data: https:">
<head>
<title>Demo</title>
<link rel="icon" type="image/png" href="./favicon.ico">
</head>
<body style="background-color:#F0F8FF" style="font-size: 18px; font-family:verdana,arial,tahoma,serif;">
<form name="demoForm" style="background-color:#92a8d1">
<fieldset>
<input id="dataRequest" type="request" method="POST" value=""/>
<button type="submit" value="Run" />
</fieldset>
</form>
</body>
</html>
package main
import (
"fmt"
"net/http"
"log"
)
func index() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
http.ServeFile(w, r, "visible/index.html")
return
case "POST":
fmt.Println("Posted a request!")
err := r.ParseForm();
if err != nil {
log.Fatal(err)
}
request := r.Form.Get("dataRequest")
fmt.Println(request)
return
}
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", index())
http.ListenAndServeTLS(":443", "./server.crt", "./server.key", mux)
}
I'am generating QR codes and right after I need to show them in an HTML without saving them as images.
So far I can generate them but I have problems rendering them in the HTML
I have here the golang code that generates the QR and the HTML template that try to render them
golang
import (
"fmt"
"github.com/gin-gonic/gin"
qrcode "github.com/skip2/go-qrcode"
)
func renderQRExport(c *gin.Context){
var images [][]byte
var img []byte
var err error
for i := 0; i < 25; i++ {
img, err = qrcode.Encode("https://example.org", qrcode.Medium, 256)
images = append(images, img)
if err != nil {
fmt.Print(err)
}
}
render(c, gin.H{
"images": images,
}, "qr.html")
}
HTML Template
<!doctype html>
<html class="no-js" lang="">
<head>
<title>QR export</title>
{{template "imports.html"}}
</head>
<body>
<div class="margin-body-log-in-worker">
<div class="row">
{{range .images}}
<div class="col-4 col-sm-4 col-md-3 col-xl-2 center">
<img src="data:image/png;base64,{{.image}}" class="img-fluid image-dashboard" />
</div>
{{end}}
</div>
</div>
</body>
</html>
One of the things that I'am not able to do, as they say in this article:
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang
and also the Encode method itself says "To serve over HTTP, remember to send a Content-Type: image/png header."
How can I set properly the content type in the request using gingonic and how to decode properly in the HTML?
I solved my own question thanks to this article: https://www.socketloop.com/tutorials/golang-encode-image-to-base64-example
The proble is that i needed to Encode it to String with 'imgBase64Str := base64.StdEncoding.EncodeToString(buf)'
So the final code to work is as follows:
Golang
func renderQRExport(c *gin.Context){
var images []string
var img []byte
var err error
for i := 0; i < 25; i++ {
img, err = qrcode.Encode("https://example.org", qrcode.Medium, 256)
img2 := base64.StdEncoding.EncodeToString(img)
images = append(images, img2)
if err != nil {
fmt.Print(err)
}
}
render(c, gin.H{
"images": images,
}, "qr.html")
}
HTML
<!doctype html>
<html class="no-js" lang="">
<head>
<title>QR export</title>
{{template "imports.html"}}
</head>
<body>
<div class="margin-body-log-in-worker">
<div class="row">
{{range .images}}
<div class="col-4 col-sm-4 col-md-3 col-xl-2 center">
<img src="data:image/png;base64,{{.}}" class="img-fluid image-dashboard" />
</div>
{{end}}
</div>
</div>
</body>
</html>
I'm trying to load template page.gohtml from folder cms/template. When trying to view in Firefox browser it load Blank.
handler.go file
var Tmpl = template.Must(template.ParseGlob("../templates/*"))
func ServeIndex(w http.ResponseWriter, r *http.Request) {
p := &Page{
Title: "Go Projects CMS",
Content: "Welcome to the Home Page!",
Posts: []*Post{
{
Title: "Hello World!",
Content: "Hey y'all, Thanks for coming",
DatePublished: time.Now(),
},
{
Title: "This Has Comments",
Content: "Atlassian Just Bought Trello...GO!",
DatePublished: time.Now().Add(-time.Hour),
Comments: []*Comment{
{
Author: "Davy Jones",
Content: "This is something to say about something",
DatePublished: time.Now().Add(-time.Hour / 2),
},
},
},
},
}
Tmpl.ExecuteTemplate(w, "page", p)
}
cmd/main.go file
func main() {
r := mux.NewRouter()
r.HandleFunc("/", cms.ServeIndex)
fmt.Println("Server running at port 3000")
go http.ListenAndServe(":3000", r)
fmt.Scanln()
}
templates/page.gohtml
{{ define "page" }}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ .Title }}</title>
<link rel="stylesheet" href="https://unpkg.com/tachyons#4.10.0/css/tachyons.min.css"/>
</head>
<body class="w-100 sans-serif bg-white">
<h1>Welcome</h1>
<div class="baskerville pb5">
{{ .Content }}
{{if .Posts}}
{{range .Posts}}
{{template "post" .}}
{{end}}
{{end}}
</div>
</body>
</html>
{{ end }}
I found the issue when I used error handling.
if err := Tmpl.ExecuteTemplate(w, "page", p); err != nil {
log.Printf("Template error: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
Which printed "no such template comments" while I was using defined "comment" inside comment.gohtml
Sorry for posting this question, I recently started GoLang.
I am just starting with learning web development, Go, and Ajax but I am having trouble seeing what is going wrong. I am trying to simply send data back and forth between the client and the server. With the Ajax request, I am sending data from the form to the server but it does not seem to reach the server because the log doesn't print "in posthandler" which leads me to think something is wrong with the ajax request. Attached is the main.go, index.html, and js/getData.js with all the relevant code.
main.go
package main
import (
"fmt"
"net/http"
"io/ioutil"
"log"
)
var INDEX_HTML []byte
func main(){
fmt.Println("starting server on http://localhost:8888/\nvalue is %s", value)
http.HandleFunc("/", IndexHandler)
http.HandleFunc("/post", PostHandler)
http.ListenAndServe(":8888", nil)
}
func IndexHandler(w http.ResponseWriter, r *http.Request){
log.Println("GET /")
w.Write(INDEX_HTML)
}
func PostHandler(w http.ResponseWriter, r *http.Request){
r.ParseForm()
log.Println("in posthandler", r.Form)
var value = r.FormValue("textfield")
w.Write([]byte(value))
}
func init(){
INDEX_HTML, _ = ioutil.ReadFile("./html/index.html")
}
index.html
<!doctype html>
<html>
<head>
<title>Page Title</title>
<script src="js/getData.js"></script>
</head>
<body>
<form action="/post" method="post">
<textarea type="text" name="input" id="textfield"></textarea>
<br />
<input type="submit" name="button" id="button" value="Send" onclick="loadXMLDoc()"/>
</form>
<div id="fromserver">
</div>
</body>
</html>
js/getData.js
function loadXMLDoc() {
var xmlhttp;
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("fromserver").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("POST","post",true);
xmlhttp.send();
}
There are two things:
No handler present to render assest (in this case js/.)
Form by itself get submitted due to "submit" HTML element.
here is your updated code
main.go
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
var INDEX_HTML []byte
func main() {
fmt.Println("starting server on http://localhost:8888/\nvalue is %s", "asdf")
http.HandleFunc("/", IndexHandler)
http.HandleFunc("/post", PostHandler)
serveSingle("/js/getData.js", "./js/getData.js")
http.ListenAndServe(":8888", nil)
}
func serveSingle(pattern string, filename string) {
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filename)
})
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
log.Println("GET /")
w.Write(INDEX_HTML)
}
func PostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
log.Println("in posthandler", r.Form)
var value = r.FormValue("textfield")
w.Write([]byte(value))
}
func init() {
INDEX_HTML, _ = ioutil.ReadFile("./html/index.html")
}
index.html
<!doctype html>
<html>
<head>
<title>Page Title</title>
<script src="js/getData.js"></script>
</head>
<body>
<form action="/post" method="post">
<textarea type="text" name="input" id="textfield"></textarea>
<br />
<input type="button" name="button" id="button" value="Send" onclick="loadXMLDoc()"/>
</form>
<div id="fromserver">
</div>
</body>
</html>