Search code examples
haskellhappstackdigestive-functors

How do I solve "HTTP request failed with: when is not a field" runtime errors in digestive-functors code?


I have a simple and incomplete Happstack application, that consists of a digestive-functors form defined as follows:

setRecFormSpec :: Monad m => Form Text m Reminder
setRecFormSpec = Reminder
    <$> "progname" .: string Nothing
    <*> "channel" .: string Nothing
    <*> "when" .: localTimeFormlet "%d/%m/%Y" "%H:%M" Nothing
    <*> "recordLimit" .: stringRead "Can't parse number" (Just 7)

and its view defined as follows:

setRecView :: View H.Html -> H.Html
setRecView view = do
        H.div ! A.class_ "container" $ do
            H.h1 "Set Record Reminder"
            childErrorList "" view

            divFormGroup $ do
                label "progname" view "Program Name:"
                formControl $ inputText "progname" view

            divFormGroup $ do
                label "channel" view "Channel:"
                formControl $ inputText "channel" view

            divFormGroup $ do
                label "when" view "When:"
                formControl $ inputDate "when" view

            divFormGroup $ do
                label "recordLimit" view "Recording Limit (days):"
                formControl $ inputText "recordLimit" view

            divFormGroup $ do
                formControl $ inputSubmit "Signup"

-- divFormGroup -- candidate to go into a Bootstrap library
divFormGroup :: H.Html -> H.Html
divFormGroup h =
    H.div ! A.class_ "form-group" $ h

-- formControl -- candidate to go into a Bootstrap library
formControl :: H.Html -> H.Html
formControl h = (h ! A.class_ "form-control")

Reminder is defined as follows:

data Reminder = Reminder {
        programName     :: String    -- ^ name of program
    ,   channel         :: String    -- ^ name of broadcast channel
    ,   firstShowing    :: LocalTime  -- ^ time of first showing
    ,   timerPeriodDays :: Integer     -- ^ how far in advance we can set timer, in days
} deriving (Show)

When I browse to the path for the form (/setrec) I get a blank page with the following error message printed on the console:

HTTP request failed with: when is not a field

I've found where that error message is defined (in https://github.com/jaspervdj/digestive-functors/blob/7e50d5686abc4b39389ed195693660d758987c7c/digestive-functors/src/Text/Digestive/Form/Internal.hs ) but I can't see from there why the 'when' field would not be found.

What is the problem here?

How do I debug this kind of issue?

Here's a link to the whole code on github, in case you need to look more deeply at the code:

https://github.com/nmbooker/recremind


Solution

  • I solved it, with a variation on Pseudoradius' solution.

    I defined a new view thus:

    dateTimeView view = do
        divFormGroup $ do
            label "date" view "When (Date):"
            formControl $ inputText "date" view
    
        divFormGroup $ do
            label "time" view "When (Time):"
            formControl $ inputText "time" view
    

    and in my form I used it with subView, thus:

    setRecView :: View H.Html -> H.Html
    setRecView view = do
            H.div ! A.class_ "container" $ do
                -- ...
    
                divFormGroup $ do
                    label "channel" view "Channel:"
                    formControl $ inputText "channel" view
    
                dateTimeView $ subView "when" view
    
                divFormGroup $ do
                    label "recordLimit" view "Recording Limit (days):"
                    formControl $ inputText "recordLimit" view
    
                divFormGroup $ do
                    formControl $ inputSubmit "Signup"
    

    Then the runForm call was able to find the when field and get the date and time from it.

    I could parameterise dateTimeView with dateLabelText and timeLabelText, and probably will, but the above should be enough for illustrative purposes.