如何在 Yesod 中为 selectField 构建预选选项?

How to build a pre-selected option for a selectField in Yesod?

(This was asked before but it has no answers).

我在数据库中有一个国家列表:

share [mkPersist sqlSettings] [persistLowerCase|
Country
  name Text
  UniqueCountryName name
  deriving Show
|]

而且我可以向 select 其中之一展示表格:

countries = do
  rows <- runDB $ selectList [] [Asc CountryName]
  optionsPairs $ map (\ r -> (countryName $ entityVal r, entityKey r)) rows

surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
  (countryR, countryV) <- mreq (selectField countries) "" Nothing

我知道我应该将最后一行中的 Nothing 替换为所需的默认值,但我仍然不知道该怎么做。查看 mreq and the optionsPairs 签名,我的想法是,在这种情况下,我应该提供默认国家/地区的 Maybe Option,但我的尝试引发了太多类型错误,可能我离正确答案还很远。

Yesod 书中有一个示例使用似乎比我试图实现的更简单,所以我不确定如何推断它。

顺便说一句,我正在从数据库中获取默认国家/地区,因此我不需要对其内部 ID 进行硬编码:

defaultCountry = do
  row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
  (countryName $ entityVal row, entityKey row)

当我将它作为参数传递给 mreq 时,出现以下错误:

Couldn't match type ‘(,) Text’ with ‘HandlerFor site’ Expected type: HandlerFor site (Key record) Actual type: (Text, Key record)

这是 defaultContry 函数 ((countryName $ entityVal row, entityKey row)) 的最后一行。我知道我应该从一对中取出 Key record 并在 HandlerFor site 中取出 return 但同时我也得到:

Couldn't match expected type ‘Maybe (Key Country)’ with actual type ‘HandlerFor site0 (Key record0)’

(countryR, countryV) <- mreq (selectField countries) "" defaultCountry 行中。我将其解释为“你传递给我一个 HandlerFor site0 (Key record0) 但我只接受 Maybe (Key Country) 这似乎与第一个错误冲突......

(countryName $ entityVal row, entityKey row) 行中我还看到:

Couldn't match expected type ‘Entity Country’ with actual type ‘Maybe (Entity Country)’

row 参数中。我知道我应该从 Maybe 中提取 Entity Country,但是如果我进行模式匹配并仅传递 Entity Country(即:Just (Entity countryId country) -> (countryName $ entityVal (Entity countryId country), entityKey (Entity countryId country)),我仍然会遇到第一个错误。

提前致谢。

好的,这看起来像是一些打字错误。第一个

Couldn't match type ‘(,) Text’ with ‘HandlerFor site’ Expected type: HandlerFor site (Key record) Actual type: (Text, Key record)

来自于在你的 do 符号中没有使用 return 来提升 monad 的值:

defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
  row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
  return (countryName $ entityVal row, entityKey row)

row

上的错误

Couldn't match expected type ‘Entity Country’ with actual type ‘Maybe (Entity Country)’

是因为是Maybe,所以更正一下

defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
  Just row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
  return (countryName $ entityVal row, entityKey row)

现在 defaultCountry 是一个很好的 monad,您应该可以在其他代码中使用它。但是要小心第三个错误

Couldn't match expected type ‘Maybe (Key Country)’ with actual type ‘HandlerFor site0 (Key record0)’

您需要从 HandlerFor monad 中解包值,然后将其重新包装在 Maybe

surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
  (defaultName, defaultKey) <- defaultCountry -- (defaultName, defaultKey) :: (Text, Key record)
  (countryR, countryV) <- mreq (selectField countries) "" (Just defaultKey)