2017年10月22日日曜日

Empty YoshidaとYesodのForm

AFormとMForm


YesodにはAFormとMFormがある、「あぷりかてぃぶふぉーむ」「モナドふぉーむ」らしいが、名前をみても何が違うのが分からないのがYesod...簡単にいうと、AFormは「お手軽版」でMFormが「好きにやれよ版」。

だと思ってる...

Formの情報をhaskellの型へ流し込んだり、その逆をやったりするもの、Formをいじくる関数を定義しておいて、generateFormPost関数とかでフォームを作成する、なんでGetとかPostでフォームの作成関数が違うのかは、CSRFとかのタグの出力があるとかないとかでちがいがある。



サンプルはこちらに置いときます。

AForm


ほとんどの場合が、これで済みそうな感じ、普通のフォームを上から並べてくならAFormで十分。
ただ、renderDivs関数とかでくるむ必要があるので、ちょっと細工をしたい場合に、邪魔になるケースがある、多分こでが気に入らなかったらMForm使えってことかな。
その他に、 renderDivsNoLabels関数とかrenderTable関数とかある、サンプルはrenderBootstrap3をBootStrap用の3種類のフォームで出力してみた。

-- Formの情報がここにはいる
data FileForm = FileForm {
    fileInfo :: FileInfo
  , inpText :: Text
}

fileUploadAFormInline :: Form FileForm
fileUploadAFormInline = renderBootstrap3 BootstrapInlineForm $ getAform

fileUploadAFormBasic :: Form FileForm
fileUploadAFormBasic = renderBootstrap3 BootstrapBasicForm $ getAform

fileUploadAFormHorizon :: Form FileForm
fileUploadAFormHorizon = renderBootstrap3 (BootstrapHorizontalForm (ColXs 2) (ColXs 8) (ColXs 2) (ColXs 6)) $ getAform

getAform :: AForm Handler FileForm
getAform = FileForm
    <$> fileAFormReq fs <*> areq textField tfs Nothing
    where fs = FieldSettings {
            fsLabel = "ファイル"
          , fsTooltip = Nothing
          , fsId = Nothing
          , fsName = Just "media"
          , fsAttrs =
              [   ("class", "form-group")
                , ("placeholder", "File description")
              ]
          }
          tfs = FieldSettings {
            fsLabel = "なんかいれろ"
          , fsTooltip = Nothing
          , fsId = Just "inptext"
          , fsName = Just "inptext"
          , fsAttrs =
              [   ("class", "form-group form-control")
                , ("placeholder", "input text")
              ]
          }


フォームの情報を取得する変数を<$>と<*>でいれていく、Formコントロールにスタイル等を設定したい場合は、FieldSettingsで属性情報を追加する。

でこれをHandlerで走らせて、Widgetを取得する

getFormexamR :: Handler Html
getFormexamR = do
  (formAWidgetBasic, formAEnctypeBasic) <- generateFormPost fileUploadAFormBasic
  (formAWidgetInline, formAEnctypeInline) <- generateFormPost fileUploadAFormInline
  (formAWidgetHorizon, formAEnctypeHorizon) <- generateFormPost fileUploadAFormHorizon
  ((res, widget), enctype) <- runFormPost fileUploadMForm
  defaultLayout $ do
        setTitle "Form Example!!!"
        $(widgetFile "formexam")

MForm


こっちは細かくフォームを作成できる方、mreqでつなげるぐらいで、基本的にAFormと一緒、mreqでFormから値を取り出すときに、ResultとViewが別々にとれるので、手動でFileFormへつめてやるところぐらいが違う、HTMLを細かく調整できる。
fileUploadMForm :: Html -> MForm Handler (FormResult FileForm, Widget)
fileUploadMForm extra = do
    let fsMedia = FieldSettings {
            fsLabel = ""
          , fsTooltip = Nothing
          , fsId = Nothing
          , fsName = Just "media"
          , fsAttrs =
              [   ("class", "uploadFile")
                , ("style", "display:none")
                , ("placeholder", "")
              ]
        }
    let fsText = FieldSettings {
            fsLabel = "なんか"
          , fsTooltip = Nothing
          , fsId = Nothing
          , fsName = Just "inptext"
          , fsAttrs =
              [   ("class", "form-group form-control")
                , ("placeholder", "")
              ]
        }

    (fileInfoRes, fileInfoView) <- mreq fileField fsMedia Nothing
    (inpTextRes, inpTextView) <- mreq textField fsText Nothing
    let fileRes = FileForm <$> fileInfoRes <*> inpTextRes
    let widget = do
            [whamlet|
                #{extra}
                <label>
                    <div class="form-group">
                        <span class="btn btn-default">Upload
                            ^{fvInput fileInfoView}
                        ^{fvInput inpTextView}
            |]
    return (fileRes, widget)

これをHandlerでつかう、resにはFileFormでwidgetにはwhamletで作成したwidgetがはいる。
...
((res, widget), enctype) <- runFormPost fileUploadMForm
...

出力はこんな感じ




HTMLの出力は4種類出力してみましたが、BootstrapとHTMLの知識は皆無ですので、あまり突っ込まないでください。


0 件のコメント:

コメントを投稿