7

さまざまな数の入力フィールドを持つフォームを動的に生成するにはどうすればよいですか?

私が管理した最も近いものは次のとおりです。

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

しかし、これは結果の型Textを持ち、意図したとおりではなく、 のインスタンスである[Text]偶然を所有しています。たとえば、 で失敗します。TextMonoidInt

私はいくつかのフォームを組み合わせた別の試行を行っていますが、どういうわけかこのおもちゃの例でしか機能しませんが、実際の試行は奇妙に失敗します。とにかく、私はこれが正しいアプローチだとは思わない:

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|]
4

2 に答える 2

6

当たり前ですが、実際にはモナド形式を使用するのは簡単です (以下のコードを参照)。

私の主な頭痛の種は、回答を受け取るハンドラーが対応する質問も推測できるようにするための追加のテキスト フィールドです。これらのテキスト フィールドを非表示にするか、編集不可にするか、別の方法を見つけることができるかもしれません (ただし、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)

常に結果を常に最も外側のコンストラクターにラップするなど、私には手がかりのない醜いものがまだいくつかありますが、FormSuccessそれは実際には各ユースケースに依存すると思います (たとえば、単一の FormFailure または FormMissing はおそらくフォーム全体を失敗させるはずです) /missing も同様ですが、これが望ましくない場合もあります。)

すべての圧縮と解凍はおそらくもっときちんと行うことができますが、私の場合は、結合されたフィールドを作成するだけだと思いますtextintField. やり方はわかると思いますが、フィールドを結合する機能があればいいですね。

于 2012-08-30T09:40:01.577 に答える