我如何创建一个 Yesod 表单,我可以从下拉列表中 select 将列表作为参数传递?

How can I create a Yesod form where I can select from a dropdown list where the list is passed as an argument?

我想创建一个表单,在其中传递一个 [a] 一个参数并取回一个 MForm Handler (FormResult a, Widget)

我曾尝试使用 selectFieldList 等函数来实现此功能,但未能找到解决方案。我无法在 google 上的任何地方找到答案。我发现了很多示例,其中下拉列表被用作较大表单中的单个字段,但 none 其中下拉列表是整个表单本身。

编辑:

我已经成功制作了一个可以编译的表格。不幸的是,我无法判断它是否按照我想要的方式工作,因为我无法渲染它。

以下是我正在使用的关键函数(它们都可以编译):

mkCityStringM :: [PG.DbCity] -> [(T.Text, PG.DbCity)]
mkCityStringM xs = zip (map (T.pack . showDbCity) xs) xs

data ContainCity =
  ContainCity
    { getCity :: PG.DbCity
    }
  deriving (Show)

ambiguityForm :: [PG.DbCity] -> AForm Handler ContainCity
ambiguityForm cities = ContainCity 
   <$> areq (selectFieldList cityMap) "City" Nothing
  where
    cityMap :: [(T.Text, PG.DbCity)]
    cityMap = W.mkCityStringM cities

问题是当我尝试实际使用这个 table 时,我 运行 遇到了问题。这是对我来说工作得很好的代码:

locationForm :: Html -> MForm Handler (FormResult BasicLocation, Widget)
locationForm = renderDivs $ BasicLocation
  <$> areq textField "City:" Nothing
  <*> areq textField "Country:" (Just "United States")

postAmbiguityR :: [PG.DbCity] -> Handler Html
postAmbiguityR cs = do 
  (widget, enctype) <- generateFormPost locationForm
  defaultLayout $ do 
  [whamlet|
    <p>who cares
  |]  

另一方面,我有这段代码:

postAmbiguityR :: [PG.DbCity] -> Handler Html
postAmbiguityR cs = do 
  (widget, enctype) <- generateFormPost (ambiguityForm cs) --only difference
  defaultLayout $ do 
  [whamlet|
    <p> WHATEVER
  |]  

这给我带来了这个错误:

    • Couldn't match expected type ‘blaze-markup-0.8.2.5:Text.Blaze.Internal.Markup
                                    -> MForm (HandlerFor Base) (FormResult a0, xml0)’
                  with actual type ‘AForm Handler ContainCity’
    • Possible cause: ‘ambiguityForm’ is applied to too many arguments
      In the first argument of ‘generateFormPost’, namely
        ‘(ambiguityForm cs)’
      In a stmt of a 'do' block:
        (widget, enctype) <- generateFormPost (ambiguityForm cs)
      In the expression:
        do (widget, enctype) <- generateFormPost (ambiguityForm cs)
           defaultLayout
             $ do (do (asWidgetT . toWidget)
                        ((blaze-markup-0.8.2.5:Text.Blaze.Internal.preEscapedText . T.pack)
                           "<html><header></header>
<form method="post" action="")
                      ....)
    |
132 |   (widget, enctype) <- generateFormPost (ambiguityForm cs)
    |                                          ^^^^^^^^^^^^^^^^

这条错误消息对我来说没有意义。它说一个可能的原因是 ambiguity form is applied to too many arguments 但似乎并非如此,因为表格采用了 PG.DbCity 的列表,而这正是我提供的。

问题是 ambiguityFormAForm,但 generateFormPost 需要 MForm。要将其转换为适合渲染的 MForm,您需要使用 renderDivs,就像您在 locationForm 示例中所做的那样。您可以 或者 ambiguityForm 的定义中执行此操作,这会将其 type/defintion 更改为如下所示:

ambiguityForm :: [PG.DbCity] -> Html -> MForm Handler (FormResult ContainCity, Widget)
ambiguityForm cities = renderDivs $ ContainCity ...

可以保持ambiguityForm不变,在使用处加上renderDivs

postAmbiguityR :: [PG.DbCity] -> Handler Html
postAmbiguityR cs = do 
  (widget, enctype) <- generateFormPost (renderDivs (ambiguityForm cs))
  defaultLayout $ do 
  [whamlet|
    <p> WHATEVER
  |]