Search code examples
formsgogo-templatestexttemplate

Go text/template Form handling, with custom FuncMap - function returning blank string outputs garbage


Using Go html/template functionality, with custom FuncMap. The custom function I've defined "isChecked(checkName string, form url.Values)" returns the string "checked" if the checkbox with checkName exists in the form, and a blank string if it does not. It works fine, but the curious thing is on the completed HTML for an un-checked checkbox, I am seeing the string "ZgotmplZ" where there should be no string at all. Here is the main.go program that sets up the FuncMap:

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "net/url"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.New("").Funcs(fm).ParseFiles("templates/check-box.html"))
}

var fm = template.FuncMap{
    "isChecked": isChecked,
}

func isChecked(checkName string, form url.Values) string {
    if form.Has(checkName) {
        return "checked"
    }
    return ""
}

func checkboxHandler(w http.ResponseWriter, r *http.Request) {
    err := r.ParseForm()
    if err != nil {
        log.Fatalln(err)
    }

    err = tpl.ExecuteTemplate(w, "check-box.html", r.Form)
    if err != nil {
        log.Fatalln(err)
    }
}

func main() {
    http.HandleFunc("/checkbox/", checkboxHandler)

    err := http.ListenAndServe(":8080", nil)
}

Here is the template:

<!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>Checkbox Control</title>
</head>
<body>

    <h1>Go html/template Form Handling - Checkbox</h1>

    <div>
    Form Data: {{.}}
    </div>

    <form action="/checkbox/" method="POST">

        <div>
            <label for="checkbox">Check Box</label>
            <input type="checkbox" name="check1" id="checkbox" value="check1" {{isChecked "check1" .}}>Check 1
            <input type="checkbox" name="check2" id="checkbox" value="check2" {{isChecked "check2" .}}>Check 2
            <input type="checkbox" name="check3" id="checkbox" value="check3" {{isChecked "check3" .}}>Check 3
        </div>

        <div>
            <button type="submit">Submit</button>
        </div>

    </form>

</body>
</html>

The result of submitting the form and checking the checkboxes is good. But when I examine source, I get this funny string "ZgotmplZ" for checkboxes that are not checked (in other words, it seems the custom function in the FuncMap is not returning a blank string for un-checked checkboxes):

        <div>
            <label for="checkbox">Check Box</label>
            <input type="checkbox" name="check1" id="checkbox" value="check1" checked>Check 1
            <input type="checkbox" name="check2" id="checkbox" value="check2" ZgotmplZ>Check 2
            <input type="checkbox" name="check3" id="checkbox" value="check3" ZgotmplZ>Check 3
        </div>

Also wondering if anyone has other suggestions on how to propate checkbox "checked" states to an html template.

Thanks!


Solution

  • The template emits ZgotmplZ because it does not like an empty string in an attribute context. Fix by doing the following.

    Return bool from isChecked:

    func isChecked(checkName string, form url.Values) bool {
         return form.Has(checkName) 
    }
    

    Use an if action in the template:

    {{if isChecked "check1" .}}checked{{end}}