Skip to content

Instantly share code, notes, and snippets.

@benpate
Last active October 8, 2024 12:44
Show Gist options
  • Save benpate/f92b77ea9b3a8503541eb4b9eb515d8a to your computer and use it in GitHub Desktop.
Save benpate/f92b77ea9b3a8503541eb4b9eb515d8a to your computer and use it in GitHub Desktop.
Demonstration of Template Fragments using the standard Go template library
package main
import (
"html/template"
"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://unpkg.com/missing.css@1.1.1"/>
<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")
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 := make(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)
http.ListenAndServe(":80", nil)
}
@benpate
Copy link
Author

benpate commented Jan 25, 2024

Good suggestion. It worked when I posted it.. I swear ;)

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