Sawyer
Sawyer

Reputation: 15917

playframework 2.x form redirect with prefill

I'm trying to implement a user login form, I want to achieve:

  1. when username doesn't exist in DB, return a flash message with previous form data prefilled.
  2. if any server side validation errors happened, return back to previous page, with old data pre-filled, display the errors messages along side.

The problem now is, if I use flash scope, I need to use Redirect after post, but this will lose the pre-filled data. If I use any status other than Redirect, I can't put data into flash scope.

What did I missing?

Upvotes: 1

Views: 972

Answers (2)

Michael Zajac
Michael Zajac

Reputation: 55569

Don't use a Redirect for a failed login. You can return the same Form back to the login view with extra errors attached to it.

Something like this:

loginForm.bindFromRequest.fold(
    formWithErrors => views.html.login(formWithErrors),
    credentials => {
         if(authenticate(credentials)) // dummy implementation
             Redirect(controllers.Application.index)
         else
             BadRequest(views.html.login(loginForm.fill(credentials).withGlobalError("Incorrect login credentials")))
    }
)

Then your view signature would look something like this:

@(loginForm: Form[Credentials])

@* Displays the first global error from the form, if any. *@
@loginForm.globalError.map{error => 
    <h3>@error.message</h3>
}

And you'd pre-fill the form with values as before (I hope).

If there are multiple global errors, you can access them with globalErrors as it will access a Seq[FormError] instead of Option[FormError].

You can also attach errors to specific Form keys.

 loginForm.withError("email", "I don't like your email.")

And would access them similarly:

 @loginForm.error("email").map{ error =>
     @error.message
 }

Upvotes: 3

biesior
biesior

Reputation: 55798

You are using wrong concept, take a look to the Handling form submission doc, section: Validating a form in an Action

  • If form contains errors you are returning BadRequest (not Redirect)
  • If form IS valid anyway next check (i.e. DB query) returns an error you should do exactly the same thing as in formWithErrors so render the view passing incoming form to it (userData)
  • Finally if everything's OK, you can make your operation and redirect the user i.e. to main page or something...

Pseudo code (basing on doc):

def userPost = Action { implicit request =>

  userForm.bindFromRequest.fold(
    formWithErrors => {
      BadRequest(views.html.user(formWithErrors))
    },
    userData => {
      // Check whatever you need...
      if (afterCheckSomethingIsWrong){
        // if something's wrong fill the `userForm` with `userData` and render the same view again...
        // You can use flash scope here i.e. for placing error message
        BadRequest(views.html.user(userForm.fill(userData))).flashing("error" -> "The account doesn't exist")
      } else {
        // if everything is OK, redirect to some page, outside the form handling process, i.e. main page
        Redirect(routes.Application.index).flashing("success" -> "Fine you're logged now")
      }

    }
  )

} 

Upvotes: 2

Related Questions