errorList ++> (((,) <$> password1 <*> password2) `transformEither` samePassword) `transformEither` minLength 6
That will create a form with two password fields. Then it uses transformEither to confirm that both fields are the same, and if so, returns their value, otherwise it returns a validation error. It also checks that the password is at least 6 characters long. That password form can then be used in the overall account create form. Here is the complete example:
newAccountForm :: (Functor v, MonadIO v) => AcidState AuthState -> AuthForm v (AuthId, UserPassId)
newAccountForm authStateH =
(R.fieldset
(errorList ++>
(R.ol $ (((,) <$> username <*> password <* submitButton)))
`transformEitherM`
createAccount))
where
submitButton = R.li $ (mapView (\html -> html ! A.class_ "submit") $ inputSubmit "Create Account")
username = R.li $ errorList ++> ((label ("username: " :: String) ++> inputText mempty) `transformEither` (minLength 1))
password1 = R.li $ label ("password: " :: String) ++> inputPassword
password2 = R.li $ label ("confirm password: " :: String) ++> inputPassword
password =
errorList ++> (((,) <$> password1 <*> password2) `transformEither` samePassword) `transformEither` minLength 6
samePassword (p1, p2) =
if p1 /= p2
then (Left $ PasswordMismatch)
else (Right p1)
createAccount (username, password) =
do passHash <- liftIO $ mkHashedPass password
r <- update' authStateH $ CreateUserPass (UserName username) passHash
-- fixme: race condition
case r of
(Left e) -> return (Left $ UPE e)
(Right userPass) ->
do authId <- update' authStateH (NewAuthMethod (AuthUserPassId (upId userPass)))
return (Right (authId, upId userPass))
The <select> variation is a bit trickier. There is no reason why the validation can not be done correctly on the server-side, but for a system like that, it seems like you might also want to have some clientside actions happening. For example, disabling/hiding the 'forbidden' actions via javascript.
Right now that would require you to manually attach an onchange handler to the select element to enable/disable other fields. Which is possible.. just not elegant.
reform (and similar libraries) are great for web 1.0. Making things more web 2.0 is still largely unexplored. Though I am hoping that things like Fay will open the doors to making things like client-side validation easier.