質問

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}}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top