英文:
Unpacking <select> fields with gorilla/schema
问题
我正在使用gorilla/schema将r.PostForm
解析为一个结构体。
我的问题是,我正在尝试找到一种“合理”的方法来获取<select>
元素的选定值,以便我可以轻松地使用html/template
重新选择该字段(即在从会话重新填充表单时)。需要注意的是,没有一种简单的方法来测试相等性,并且只需将结构体的实例传递给RenderTemplate
。
为了说明我的问题:
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" {
// 省略了错误处理代码,但请相信,它是存在的!
err = r.ParseForm()
err = decoder.Decode(listing, r.PostForm)
err = listing.Validate() // 检查字段长度,因为我使用的是无模式的数据存储
}
<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>
当我将listing
的实例传递给模板时,我想要能够做到以下操作:
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>
显然,这样做是行不通的。我考虑过使用template.FuncMap
作为可能的解决方案,但我不确定在我想要将整个listing
实例传递给模板时如何使用它(即而不是逐个字段地传递)。如果可能的话,我还希望尽量减少结构体中不必要的字段。我可以为每个值(例如Fulltime bool
)添加布尔字段,但如果用户返回并编辑其他字段,我还需要编写代码将其他字段更改为“false”。
有没有一种方法可以以与template/html
的限制相协调的方式实现这一点?
英文:
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
?
答案1
得分: 5
你可以编写一个视图来构建和表示一个select
元素:
{{define "select"}}
<select name="{{.Name}}">
{{range $a, $b := .Options}}
<option value="{{print $a}}" {{if $a == .Selected}}selected{{end}}>{{print $b}}</option>
{{end}}
</select>
{{end}}
对应的数据结构如下:
type SelectBlock struct {
Name string
Selected string
Options map[string]string
}
然后实例化它:
termSelect := SelectBlock{
Name: "term",
Selected: "",
Options: map[string]string{
"full-time": "全职",
"part-time": "兼职",
"contract": "合同工",
"freelance": "自由职业",
},
}
并设置Selected
字段:
termSelect.Selected = "full-time"
在你的表单视图中输出视图片段:
{{template "select" $termSelect}}
其中$termSelect
将是你的SelectBlock
实例。
英文:
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
.
答案2
得分: 2
对于将来使用 Go v1.2 或更高版本的其他人来说,text/template
和 html/template
现在提供了一个相等运算符(以及其他新的运算符):http://golang.org/doc/go1.2#text_template
{{if eq .Term "full-time" }}selected{{end}}
...
{{if eq .Term "freelance" }}selected{{end}}
英文:
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}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论