Create register form with password confirmation and validation messages next to field as shown on image below.
Solution:
There are many solutions to this problem. I chose tuple transformation. It provides me error on
tuple level, instead of globalErrors.
First step is to create model object:
Usercase class User(login: String, password: String)
then define form in controller for
User case class val registrationForm: Form[User] = Form(
mapping(
"login" -> nonEmptyText.verifying("user.registration.userExists", User.findByLogin(_) == None),
"passwordWithConfirmation" -> tuple(
"password" -> text(minLength = 6, maxLength = 30)
.verifying("user.registration.passwordOneDigit", name => {
(name + "A").split("\\d").size > 1
}),
"confirmation" -> text
).verifying("user.registration.passwordDontMatch", verifyPassword(_)).transform(
{ case (password, confirmation) => password},
(password: String) => ("", "")
)
)(User.apply)(User.unapply)
)
def verifyPassword(passwordWithConfirmation: Tuple2[String, String]): Boolean = passwordWithConfirmation match {
case (password: String, confirmation: String) => password.equals(confirmation)
}
The form contains
Play template for the passwordWithConfirmation which is tuple mapping for password and confirmation inputs. For this tuple I added verification rule, checking if both fields are equal. Last thing to do is to convert tuple into data that will be stored in User entity. For this purpose transform function is used. The transformation works both ways:
- from form to object
{ case (password, confirmation) => password} - from object to form
(password: String) => ("", "")
Form object may look like this:
@(registrationForm: Form[model.User])(implicit flash: Flash)
@import helper.twitterBootstrap._
@import helper._
@main {
<h2>@Messages("user.registration.registerAccount")</h2>
@helper.form(action=routes.UserCtrl.register) {
<fieldset>
@inputText(registrationForm("login"))
@inputPassword(registrationForm("passwordWithConfirmation.password"))
@inputPassword(registrationForm("passwordWithConfirmation.confirmation"))
</fieldset>
<input class="btn btn-primary" type="submit" value="@Messages("user.registration.register")" />
}
}
Last thing that I need to do is to show error message for unmatched passwords. This will not work automatically, because there is no passwordWithConfirmation element in my form. @if(registrationForm.hasErrors) {
@registrationForm.error("passwordWithConfirmation") match {
case Some(err:FormError) => {<span class="help-inline">@Messages(err.message)</span>}
case _ => {}
}
}

