I'm using gorilla/schema to unpack r.PostForm
into a struct.
My issue is that I'm trying to figure out a "sensible" way to get the selected value of a <select>
element in a way that allows me to easily use html/template
to re-select the field (i.e. when re-populating the form from a session) noting that there isn't an easy way to test for equality and just by passing an instance of the struct to RenderTemplate
.
To illustrate what I have:
type Listing struct {
Id string `schema:"-"`
Title string `schema:"title"`
Company string `schema:"company"`
Location string `schema:"location"`
...
Term string `schema:"term"`
}
if r.Method == "POST" {
// error handling code removed for brevity, but trust me, it exists!
err = r.ParseForm()
err = decoder.Decode(listing, r.PostForm)
err = listing.Validate() // checks field lengths as I'm using a schema-less datastore
<label for="term">Term</label>
<select data-placeholder="Term...?" id="term" name="term" required>
<option name="term" value="full-time">Full Time</option>
<option name="term" value="part-time">Part Time</option>
<option name="term" value="contract">Contract</option>
<option name="term" value="freelance">Freelance</option>
</select>
... and what I want to be able to do when I pass an instance of listing to the template:
renderTemplate(w, "create_listing.tmpl", M{
"listing": listing,
})
<label for="term">Term</label>
<select data-placeholder="Term...?" id="term" name="term" required>
<option name="term" value="full-time" {{ if .term == "full-time" }}selected{{end}}>Full Time</option>
<option name="term" value="part-time"{{ if .term == "part-time" }}selected{{end}}>Part Time</option>
<option name="term" value="contract" {{ if .term == "contract" }}selected{{end}}>Contract</option>
<option name="term" value="freelance" {{ if .term == "freelance" }}selected{{end}}>Freelance</option>
</select>
Obviously this won't work. I've considered template.FuncMap
as a possible solution but I'm not sure how I can use this when I want to pass the entire listing instance to the template (i.e. instead of field-by-field). I also want to, if possible, minimise unnecessary fields in my struct. I could have boolean fields for each value (i.e. Fulltime bool
, but I then need code to change the other fields to "false" if the user goes back and edits things.
Is there a way to achieve this in way that meshes well with the limitations of template/html
?
You could write a view to build and represent a select
element:
{{define "select"}}
<select name="{{.Name}}>
{{range $a, $b := .Options}}
<option value="{{print $a}}" {{if $a == .Selected}}>{{print $b}}</option>
{{end}}
</select>
{{end}}
And the corresponding data structure:
type SelectBlock struct {
Name string
Selected string
Options map[string]string
}
Then instantiate it:
termSelect := SelectBlock{
Name: "term",
Selected: "",
Options: map[string]string{
"full-time": "Full Time",
"part-time": "Part Time",
"contract": "Contract",
"freelance": "Freelance",
},
}
And set the Selected
field:
termSelect.Selected = "full-time"
And output the view fragment inside your form view:
{{template "select" $termSelect}}
Where $termSelect
would be your instance of SelectBlock
.
For others looking at this in the future, who are using Go v1.2 or later: text/template
and html/template
now offer an equality operator (amongst other new operators): http://golang.org/doc/go1.2#text_template
{{if eq .Term "full-time" }}selected{{end}}
...
{{if eq .Term "freelance" }}selected{{end}}