How can I validate a field based on another field?

186 Views Asked by At

I'm trying to have a registration form with fields like email and emailConfirmation, or password and passwordConfirmation. Validating email and password is easy, there are rules and I've written the respective functions.

The other two are harder though. I found this question and tried writing my code like this:

The form definition, using Blaze:

registrationForm :: (View Html) -> Html
registrationForm view = docTypeHtml $ do
  form ! name "registration" ! method "post" ! action "/register" $ do
    fieldset $ do
      label ! for "password" $ (text "Password")
      inputText "password" view
      errorList "password" view

      br

      label ! for "passwordConfirmation" $ (text "Password Confirmation")
      inputText "passwordConfirmation" view
      errorList "passwordConfirmation" view

and the validator:

data Password = Password { password :: Text }

validateForm :: Monad m => Form Html m Password
validateForm =
  Password
    <$> "password" .: validatePassword
  where
    validatePassword =
      validate fst' $ (,) <$> ("password"             .: D.text Nothing)
                          <*> ("passwordConfirmation" .: D.text Nothing)
    fst' (p1, p2) | p1 == p2  = Success p1
                  | otherwise = Error "Passwords must match"

But whenever I run the server I get a message saying "password is not a field". If I remove the validation and give password a simple validation, then it works as expected. Am I missing something here?

1

There are 1 best solutions below

0
On BEST ANSWER

I got help on the digestive-functors repository. Thanks cimmanon

This is the final code, note field name is now "password.p1"/"password.p2" instead of just password/passwordConfirmation.

registrationForm :: (View Html) -> Html
registrationForm view = docTypeHtml $ do
  form ! name "registration" ! method "post" ! action "/register" $ do
    fieldset $ do
      inputText "password.p1" view
      br
      inputText "password.p2" view
      errorList "password" view
data Password = Password { password :: Text }

validator is the same, except for new names:

validateForm :: Monad m => Form Html m Password
validateForm =
  Password
    <$> "password" .: validatePassword
  where
    validatePassword =
      validate fst' $ (,) <$> ("p1" .: D.text Nothing)
                          <*> ("p2" .: D.text Nothing)
    fst' (p1, p2) | p1 == p2  = Success p1
                  | otherwise = Error "Passwords must match"