Skip to content

Instantly share code, notes, and snippets.

@17twenty
Last active January 5, 2024 05:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save 17twenty/60f501a4556a6ed006283a4d0e7ca890 to your computer and use it in GitHub Desktop.
Save 17twenty/60f501a4556a6ed006283a4d0e7ca890 to your computer and use it in GitHub Desktop.
Golang Flash demo using cookies - recreate the Flask Flash library using Golang and HTMX and make life easier.
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.8.0"></script>
<script src="https://cdn.tailwindcss.com"></script>
<title>Template Fragment Example</title>
</head>
<body>
<div hx-get="/notifications" hx-trigger="load" hx-swap="outerHTML"><!-- I GET REPLACED --></div>
<h1>Template Fragment Example</h1>
<p>
This page demonstrates how to create and serve
<a href="https://htmx.org/essays/template-fragments/"
>template fragments</a
>
using the
<a href="https://pkg.go.dev/text/template">built-in template package</a>
in Go.
</p>
<p>
This is accomplished by using the "block" action in the template, which
lets you define and execute a sub-template in a single step.
</p>
<!-- Here's the fragment. We can target it by executing the "buttonOnly" template. -->
{{block "buttonOnly" .}}
<button
hx-get="/?counter={{.next}}&template=buttonOnly"
hx-swap="outerHTML"
>
This Button Has Been Clicked {{.counter}} Times
</button>
{{end}}
</body>
</html>
package main
import (
"bytes"
"encoding/base64"
"encoding/gob"
"log"
"net/http"
"time"
)
type Flash struct {
Type string // Warning | Success | Info
Title string
Content string
}
func init() {
gob.Register(&Flash{})
}
func SetFlash(w http.ResponseWriter, flashType string, title string, content string) {
// Initialize a buffer to hold the gob data.
var buf bytes.Buffer
f := Flash{
Type: flashType,
Title: title,
Content: content,
}
err := gob.NewEncoder(&buf).Encode(&f)
if err != nil {
log.Println(err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
enc := base64.URLEncoding.EncodeToString(buf.Bytes())
c := &http.Cookie{Name: "flash", Value: enc}
http.SetCookie(w, c)
}
func GetFlash(w http.ResponseWriter, r *http.Request) (Flash, error) {
var f Flash
c, err := r.Cookie("flash")
if err != nil {
switch err {
case http.ErrNoCookie:
return f, nil
default:
return f, err
}
}
// No point worrying about bad data. Just move on past.
uDec, _ := base64.URLEncoding.DecodeString(c.Value)
if err := gob.NewDecoder(bytes.NewReader(uDec)).Decode(&f); err != nil {
log.Println(err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return Flash{}, err
}
// "Delete" by setting expired cookie
http.SetCookie(w, &http.Cookie{Name: "flash", MaxAge: -1, Expires: time.Unix(1, 0)})
return f, nil
}
<div
class="fixed top-0 z-10 flex w-full flex-col items-center justify-center space-y-2"
>
{{ if eq .Type "Warning" }}
<div
class="border-l-8 border-orange-500 bg-orange-100 p-4 text-sm text-orange-700 shadow-lg"
role="alert"
style="cursor: pointer"
onclick="this.remove()"
>
<p class="font-bold">{{ .Title }}</p>
<p>{{ .Content }}</p>
</div>
{{end}} {{ if eq .Type "Success" }}
<div
class="border-l-8 border-green-500 bg-green-100 p-4 text-sm text-green-600 shadow-lg"
role="alert"
style="cursor: pointer"
onclick="this.remove()"
>
<p class="font-bold">{{ .Title }}</p>
<p>{{ .Content }}</p>
</div>
{{end}} {{ if eq .Type "Info" }}
<div
class="border-l-8 border-blue-500 bg-blue-100 p-4 text-sm text-blue-600 shadow-lg"
role="alert"
style="cursor: pointer"
onclick="this.remove()"
>
<p class="font-bold">{{ .Title }}</p>
<p>{{ .Content }}</p>
</div>
{{end}}
</div>
...
// Flash demo
unprotectedRouter.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("templates/flash.tmpl.html"))
f, err := GetFlash(w, r)
if err != nil {
log.Println("Error received", err)
}
tpl.Execute(w, f)
})
unprotectedRouter.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("templates/login.tmpl.html"))
SetFlash(w, "Warning", "This is a warning", "This is the contents - i was set via Flash()")
tpl.Execute(w, nil)
})
unprotectedRouter.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("templates/demo.tmpl.html"))
tpl.Execute(w, nil)
})
...
@17twenty
Copy link
Author

https://gist.github.com/17twenty/60f501a4556a6ed006283a4d0e7ca890#file-main-go-L15 this could either be a simple template setting the flash OR you set the flash and redirect to another and have the flash show on that page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment