2012-08-29 148 views
6

如何動態地生成不同數量的輸入字段的形式?動態表單生成與耶索德

我管理最接近的是:

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

但是這具有這樣的結果類型Text和如預期不[Text],擁有的巧合是TextMonoid的實例,例如它與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 [email protected]{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|] 

回答

6

呃,它實際上很容易使用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) 

依然還有一些醜陋的事情,我不知道的線索,像往常一樣在最外面的FormSuccess構造函數總是包裹的結果,但我想這真的取決於每個用例(例如,單個FormFailure或FormMissing應該可能會使整個表單失敗/丟失,但也許在某些情況下,這是不希望的。)

所有的壓縮和解壓縮可能會做得更整齊,但我想我的情況下,我只是創建一個合併字段textintField。我想我知道如何去做,但如果有一個功能來組合字段,它會很整潔。