Skip to content

Instantly share code, notes, and snippets.

@17twenty
Created August 15, 2023 05:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 17twenty/3248aec12444cadf6ecf0b45ec0e4109 to your computer and use it in GitHub Desktop.
Save 17twenty/3248aec12444cadf6ecf0b45ec0e4109 to your computer and use it in GitHub Desktop.
package main
import (
"html/template"
"log"
"net/http"
"strconv"
)
/***********************
This is a simple demonstration of how to use the built-in template package in Go to implement
"template fragments" as described here: https://htmx.org/essays/template-fragments/
Go accomplishes this with the {{block}} action (described here: https://pkg.go.dev/text/template)
which defines and executes a template fragment inline inside of another template. You only have
to wire up your application to use the correct template name and the fragment will be executed.
************************/
var page *template.Template
// init function sets up the template+fragment. Most of the work is actually done here.
// In a larger program, this would likely be stored in a separate file, but this makes for a
// simple example.
func init() {
page = template.New("main")
page = template.Must(page.Parse(`<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.8.0"></script>
<link rel="stylesheet" href="https://the.missing.style"/>
<title>Template Fragment Example</title>
</head>
<body>
<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>`))
}
// handleRequest does the work to execute the template (or fragment) and serve the result.
// It's mostly boilerplate, so don't get hung up on it.
func handleRequest(w http.ResponseWriter, r *http.Request) {
// Collect state info to pass to the template
counter, _ := strconv.Atoi(r.URL.Query().Get("counter"))
templateName := r.URL.Query().Get("template")
log.Println("Template name", templateName)
if templateName == "" {
templateName = "main" // default value in case the query parameter is missing
}
// Pack state info into a map to pass to the template
data := map[string]int{}
data["counter"] = counter
data["next"] = counter + 1
// Execute the template and handle errors
if err := page.ExecuteTemplate(w, templateName, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// main is the entry point for the program. It sets up and executes the HTTP server.
func main() {
http.HandleFunc("/", handleRequest)
log.Println("Running on http://0.0.0.0:8000")
http.ListenAndServe(":8000", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment