使用yesod生成动态表单

Ste*_*fen 6 haskell yesod

如何使用不同数量的输入字段动态生成表单?

我管理的最接近的是:

listEditForm :: [String] -> Html -> MForm App App (FormResult Text, Widget)
listEditForm xs = renderDivs $ mconcat [ areq textField (String.fromString x) Nothing | x <- xs]
Run Code Online (Sandbox Code Playgroud)

但是这有结果类型Text而不是[Text]预期的,由于它Text是一个实例的巧合Monoid,例如它失败了Int.

我有一个工作的替代尝试,它结合了几种形式,但不知何故它只适用于这个玩具示例,而真正的尝试失败了奇怪.无论如何,我不认为这是正确的方法:

data MapPair = MapPair { mpKey :: T.Text, mpValue :: Maybe T.Text }

editForm mmp = renderTable $ MapPair
  <$> areq textField "Key"   (mpKey  <$> mmp)
  <*> aopt textField "Value" (mpValue <$> mmp)

pair2mp (v,k) = MapPair { mpKey = v, mpValue = Just k }

getEditR = do
  sess <- getSession
  let sesslist = Map.toList $ Map.map (decodeUtf8With lenientDecode) sess  
  forms <- forM sesslist (\a -> generateFormPost $ editForm $ Just $ pair2mp a)

  defaultLayout [whamlet|
    <h1>Edit Value Pairs
    $forall (widget,enctype) <- forms
      <form method=post action=@{EditR} enctype=#{enctype}>
        ^{widget}
        <input type=submit>
  |]

  postEditR = do
    sess <- getSession
    let sesslist = Map.toList $ Map.map (decodeUtf8With lenientDecode) sess
    forM_ sesslist (\a -> do
        ((res,_),_) <- runFormPost $ editForm $ Just $ pair2mp a
        case res of
          (FormSuccess (MapPair {mpKey=mk, mpValue=(Just mv)})) -> setSession mk mv
          _ -> return ()
      )
    defaultLayout [whamlet|ok|]
Run Code Online (Sandbox Code Playgroud)

Ste*_*fen 6

Duh,实际上很容易使用monadic形式(见下面的代码).

我主要关注的是额外的文本字段,以确保接收答案的处理程序也可以推断出相应的问题.也许我可以隐藏那些文本字段,使它们不可编辑,或者找到另一种方法(但我还不太了解Html).

listEditMForm :: [(String,Int)] -> Html -> MForm App App (FormResult [(FormResult Int, FormResult Text)], Widget)
listEditMForm xs extra = do
    ifields <- forM xs (\(s,i) -> mreq intField  (String.fromString s) (Just i))
    tfields <- forM xs (\(s,i) -> mreq textField (String.fromString s) (Just $ pack s))
    let (iresults,iviews) = unzip ifields
    let (tresults,tviews) = unzip tfields
    let results = zip iresults tresults
    let views   = zip iviews tviews
    let widget = [whamlet|
        #{extra}
        <h1>Multi Field Form
        $forall (iv,tv) <- views
          Field #
          #{fvLabel iv}: #
          ^{fvInput tv} #
          ^{fvInput iv}
          <div>
      |]
    return ((FormSuccess results), widget)
Run Code Online (Sandbox Code Playgroud)

还有一些我不知道的丑陋的事情,比如总是将结果总是包装在最外层的FormSuccess构造函数中,但我想这实际上取决于每个用例(例如,单个FormFailure或FormMissing应该可能使整个表单失败/也不见了,但也许在某些情况下这不是想要的.)

所有的压缩和解压缩都可以更整齐地完成,但我想在我的情况下我只是创建一个组合字段textintField.我想我知道怎么做,但如果有一个组合字段的功能,它会很整洁.