Как обрабатывать несколько форм на одной странице, используя Suave.Experimental
Я должен создать простую страницу с несколькими формами. Я решил использовать Suave.Experimental для этой цели. Когда я нажимаю на submit
Кнопка на второй форме, я получаю следующую ошибку
Отсутствует поле формы "Второй"
WebPart
let webpart =
choose [
GET >=> OK page
POST >=> bindToForm firstForm firstHandle
POST >=> bindToForm secondForm secondHandle
]
Можно ли иметь несколько форм с Suave.Experimental?
Если так - чего мне здесь не хватало?
Если нет - какой будет подходящий подход для этого?
Минимальный пример ниже:
open Suave.Form
open Suave.Html
type FirstForm = { First : string }
type SecondForm = { Second : decimal }
let firstForm : Form<FirstForm> =
Form ([ TextProp ((fun f -> <@ f.First @>), [ ])],[])
let secondForm : Form<SecondForm> =
Form ([ DecimalProp ((fun f -> <@ f.Second @>), [])], [])
type Field<'a> = {
Label : string
Html : Form<'a> -> Suave.Html.Node
}
type Fieldset<'a> = {
Legend : string
Fields : Field<'a> list
}
type FormLayout<'a> = {
Fieldsets : Fieldset<'a> list
SubmitText : string
Form : Form<'a>
}
let form x = tag "form" ["method", "POST"] x
let submitInput value = input ["type", "submit"; "value", value]
let renderForm (layout : FormLayout<_>) =
form [
for set in layout.Fieldsets ->
tag "fieldset" [] [
yield tag "legend" [] [Text set.Legend]
for field in set.Fields do
yield div ["class", "editor-label"] [
Text field.Label
]
yield div ["class", "editor-field"] [
field.Html layout.Form
]
]
yield submitInput layout.SubmitText
]
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.Web
open Suave.Model.Binding
open Suave.RequestErrors
let bindToForm form handler =
bindReq (bindForm form) handler BAD_REQUEST
let firstHandle first =
printfn "first = %A" first
Redirection.FOUND "/"
let secondHandle second =
printfn "second = %A" second
Redirection.FOUND "/"
let page =
html [] [
head [] [ ]
body [] [
div [][
renderForm
{ Form = firstForm
Fieldsets =
[ { Legend = "1"
Fields =
[ { Label = "Text"
Html = Form.input (fun f -> <@ f.First @>) [] }
] }]
SubmitText = "Submit" }
renderForm
{ Form = secondForm
Fieldsets =
[ { Legend = "2"
Fields =
[ { Label = "Decimal"
Html = Form.input (fun f -> <@ f.Second @>) [] }
] }]
SubmitText = "Submit" }
]
]
]
|> htmlToString
let webpart =
choose [
GET >=> OK page
POST >=> bindToForm firstForm firstHandle
POST >=> bindToForm secondForm secondHandle
]
startWebServer defaultConfig webpart
1 ответ
Вы направляете один и тот же маршрут POST / к обоим обработчикам форм. У вас должен быть только один маршрут для каждого, в противном случае выполняется только один из них.
Вы можете установить различное действие формы для каждой из ваших форм и соответственно создать пути для них.
Я быстро внес эти изменения в ваш код, и теперь он должен работать:
open Suave.Form
open Suave.Html
type FirstForm = { First : string }
type SecondForm = { Second : decimal }
let firstForm : Form<FirstForm> =
Form ([ TextProp ((fun f -> <@ f.First @>), [ ])],[])
let secondForm : Form<SecondForm> =
Form ([ DecimalProp ((fun f -> <@ f.Second @>), [])], [])
type Field<'a> = {
Label : string
Html : Form<'a> -> Suave.Html.Node
}
type Fieldset<'a> = {
Legend : string
Fields : Field<'a> list
}
type FormLayout<'a> = {
Fieldsets : Fieldset<'a> list
SubmitText : string
Form : Form<'a>
}
let form action x = tag "form" ["method", "POST"; "action", action] x
let submitInput value = input ["type", "submit"; "value", value]
let renderForm action (layout : FormLayout<_>) =
form action [
for set in layout.Fieldsets ->
tag "fieldset" [] [
yield tag "legend" [] [Text set.Legend]
for field in set.Fields do
yield div ["class", "editor-label"] [
Text field.Label
]
yield div ["class", "editor-field"] [
field.Html layout.Form
]
]
yield submitInput layout.SubmitText
]
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.Web
open Suave.Model.Binding
open Suave.RequestErrors
let bindToForm form handler =
bindReq (bindForm form) handler BAD_REQUEST
let firstHandle first =
printfn "first = %A" first
Redirection.FOUND "/"
let secondHandle second =
printfn "second = %A" second
Redirection.FOUND "/"
let page =
html [] [
head [] [ ]
body [] [
div [][
renderForm "first"
{ Form = firstForm
Fieldsets =
[ { Legend = "1"
Fields =
[ { Label = "Text"
Html = Form.input (fun f -> <@ f.First @>) [] }
] }]
SubmitText = "Submit" }
renderForm "second"
{ Form = secondForm
Fieldsets =
[ { Legend = "2"
Fields =
[ { Label = "Decimal"
Html = Form.input (fun f -> <@ f.Second @>) [] }
] }]
SubmitText = "Submit" }
]
]
]
|> htmlToString
let webpart =
choose [
GET >=> OK page
POST >=> choose
[ path "/first" >=> (bindToForm firstForm firstHandle)
path "/second" >=> (bindToForm secondForm secondHandle) ]
]
startWebServer defaultConfig webpart