haskellyesod

Haskell Yesod: Sending a Post Request On Image Click


I am writing a simple website in Haskell with Yesod. I have the following hamlet

<ul id="gallery">
              $forall file <- listOfFiles
                  <form action=@{CharacterUpdateR} method="POST">
                      <input type="hidden" name="Name" value=#{characterName character} />
                      <input type="hidden" name="Portrait" value=#{file} />
                      <input type="hidden" name="Description" value=#{fromMaybe "" (characterDescription character)} />
                      <input type="image" src=#{imageFilePath $ (++) (unpack $ characterName character) ((++) "\\"  file)} name="select" alt="select" />

The following Haskell code is supposed to handle the request:

postCharacterUpdateR :: Handler Html
postCharacterUpdateR = do
    ((result, widget), enctype) <- runFormPost updateCharacterForm
    case result of
        FormSuccess (name, file, desc) -> do
            _ <- runDB $ updateWhere [CharacterName ==. name] [CharacterPortrait =.   file] 
            _ <- runDB $ updateWhere [CharacterName ==. name] [CharacterDescription =. desc]
            setMessage "Character Updated"
            redirect CharactersR
        _ -> do
            liftIO $ putStrLn $ show result
            setMessage $ "Something went wrong: "
            redirect CharactersR

The page renders fine and when the images in the gallery are clicked, a POST request is sent and received by the handler, but it always fails, with the following error message: FormFailure ["Value is required","Value is required"]

I have tried to send the post request via a Julius widget instead with ajax, but reached a similar problem. In the developer console, it seems like the payload for the sent POST request is fine, but nonetheless the handler never receives the POST parameters.


Solution

  • I fixed this issue by, rather than using Hamlet itself to create the form submission, using runFormPost to get a widget to send the request.

    updateCharacterForm :: Text -> String -> Maybe Textarea -> Html -> MForm Handler (FormResult (Text, Text, Maybe Textarea), Widget)
    updateCharacterForm name portrait desc = renderBootstrap $ (,,)
                 <$> areq hiddenField "Name" (Just name)
                 <*> areq hiddenField "Portrait" (Just $ pack portrait)
                 <*> aopt textareaField "Description" (Just desc)
    

    In conjunction with

    characterGalleryEntry :: Character -> String -> Widget
    characterGalleryEntry character file = do
      ((_, widget), enctype) <- liftHandler $ runFormPost (updateCharacterForm (characterName character) file (characterDescription character))
      [whamlet|$newline never
                      <form action=@{CharacterUpdateR} method=post enctype=#{enctype}>
                          ^{widget}
                          <image src=#{imageFilePath $ (++) (unpack $ characterName character) ((++) "\\"  file)}>
                          <input .btn type=submit value="Set Profile Picture and Update">
    |]```
    For the post itself