I'm trying to use a selectFieldList
inside a subsite form but I get the following error:
Couldn't match type 'IO' with 'HanderT master IO'
I'm running into this problem when using the following snippets, where the subsite is named TestSub
(this subsite is separated from the master site):
Types:
type TestHandler a = forall master. Yesod master
=> HandlerT TestSub (HandlerT master IO) a
type Form a = forall master. Yesod master
=> Html -> MForm (HandlerT TestSub (HandlerT master IO)) (FormResult a, WidgetT TestSub IO ())
Form & handler:
testForm :: Form (Text, Int)
testForm = renderBootstrap3 BootstrapBasicForm $ (,)
<$> areq textField (bfs MsgText) Nothing
<*> areq (selectFieldList [(MsgFirst, 1), (MsgSecond, 2)]) (bfs MsgSelect) Nothing
getTestHome :: TestHandler Html
getTestHome = do
(formWidget, _) <- generateFormPost testForm
defaultLayoutSub $ do
setTitleI MsgTest
[whamlet|^{formWidget}|]
when the select field is replaced with for instance an intField
the form and handler work as expected. While looking for the selectFieldList
on Hoogle I found that options fields (select, radio, checkbox) have a different signature (displayed below) then the "normal" fields. I suspect this difference to be the problem but haven't found a work-around without having to implement the option fields all over.
Options field signature:
selectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg)
=> [(msg, a)]
-> Field (HandlerT site IO) a
Normal field signature:
intField :: (Monad m, Integral i, RenderMessage (HandlerSite m) FormMessage)
=> Field m i
Is there a way to get the options fields to work in a subsite context, without reimplementing them?
It's usually best to run your forms in the master site, not the subsite, by calling lift
. You'll also need to modify your type synonyms a bit to match, but the basic idea is to replace:
(formWidget, _) <- generateFormPost testForm
with
(formWidget, _) <- lift $ generateFormPost testForm
EDIT
I still recommend the above approach. However, to get the alternate that you're asking for, change your type synonym to:
type Form a =
Html -> MForm (HandlerT HelloSub IO) (FormResult a, WidgetT HelloSub IO ())
and then use liftHandlerT
:
liftHandlerT $ generateFormPost testForm
Keep in mind that this isn't how subsites are designed to be used, so you'll likely end up with some more friction as you keep going.
Regarding master translations: you can definitely leverage them, you just put in a constraint along the lines of RenderMessage master MessageDataType
. That's what's used for FormMessage
all over the place.
EDIT2
One more incantation you may find useful:
defaultLayoutSub $ liftWidgetT widget