Question

I am having big difficulties following Play! 2.2.x documentation and i am currently stuck on how to display error from my form validation.

This is my code:

Route

GET         /account/create            controllers.Account.create()
POST        /account/create            controllers.Account.createAccount()

Model

public static UserAccount create(UserAccount data){
    UserAccount account = data;
    String salt     = BCrypt.gensalt();

    account.email   = data.email;
    account.salt    = salt;
    account.hash    = BCrypt.hashpw(data.hash, salt);

    account.save();
    return account;
}

Controller

// handles POST method
public static Result createAccount(){
    Form<UserAccount> userForm = form(UserAccount.class).bindFromRequest();
    if(userForm.hasErrors()){
        return badRequest();
    }else{
        UserAccount.create(userForm.get());
        Logger.info("Username is: " + userForm.get().email);
        return ok("ok, I recived POST data. That's all...");
    }
}

// Handles GET method
public static Result create(){
    return ok(
            views.html.account.form.render()
    );
}

Views

@if(form.hasGlobalErrors) {
    <p class="error">
    @form.globalError.message
    </p>
}

@helper.form(action = routes.Account.createAccount()) {
    <input type="text" name="email" placeholder="Your Email Address"/><br/>
    <input type="password" name="password" placeholder="Your Password"/><br/>

    <input type="text" name="fname" placeholder="Your First Name"/><br/>
    <input type="text" name="midname" placeholder="Your Middle Name"/><br/>
    <input type="text" name="lname" placeholder="Your Last Name"/><br/>

    <input type="text" name="dob" placeholder="Your Birthday"/><br/>
    <select name="gender" id="gender">
        <option value="1">Male</option>
        <option value="2">Female</option>
        <option value="3">Undecided</option>
    </select><br/>

    <input type="submit" value="Login" />
}

Error Message

value hasGlobalErrors is not a member of object views.html.account.form

Can anyone tell me what's wrong with my code? I am frustrated with the given example.

EDIT #1:

This is what i have done so far:

Models:

public static UserAccount create(UserAccount data){
    UserAccount account = data;
    String salt     = BCrypt.gensalt();

    account.email   = data.email;
    account.salt    = salt;
    account.hash    = BCrypt.hashpw(data.hash, salt);

    account.save();
    return account;
}

Controllers:

// HANDLES GET REQUEST
public static Result create(){
    return ok(
            views.html.account.form.render(userForm)
    );
}

// HANDLES POST REQUEST
public static Result createAccount(){
    Form<UserAccount> userForm = form(UserAccount.class).bindFromRequest();
    if(userForm.hasErrors()){
        return badRequest(views.html.account.form.render(userForm));
    }else{
        // UserAccount.create(userForm.get());
        // Logger.info("Username is: " + userForm.get().email);
        UserAccount data = userForm.get();
        return ok(data.email);
    }
}

VIEWS/TEMPLATE

@(form: Form[UserAccount])

@if(form.hasGlobalErrors) {
    <h1>Please fix the following error first</h1>
    <p>
        @form.globalError.message
    </p>
    <ul>
    @for(error <- form.globalErrors) {
        <li>@error.message</li>
    }
    </ul>
}

@helper.form(action = routes.Account.createAccount()) {
    <input type="text" name="email" placeholder="Your Email Address"/><br/>
    <input type="password" name="password" placeholder="Your Password"/><br/>

    <input type="text" name="fname" placeholder="Your First Name"/><br/>
    <input type="text" name="midname" placeholder="Your Middle Name"/><br/>
    <input type="text" name="lname" placeholder="Your Last Name"/><br/>

    <input type="text" name="dob" placeholder="Your Birthday"/><br/>
    <select name="gender" id="gender">
        <option value="1">Male</option>
        <option value="2">Female</option>
        <option value="3">Undecided</option>
    </select><br/>

    <input type="submit" value="Login" />
}

So far, according to firebug when i deliberately put errors on the form the server will return badrequest. However, no error is displayed by the template.

If i change the controller as such:

public static Result createAccount(){
    Form<UserAccount> userForm = form(UserAccount.class).bindFromRequest();
    if(userForm.hasErrors()){
        return ok(userForm.errorsAsJson().toString());
    }else{
        // UserAccount.create(userForm.get());
        // Logger.info("Username is: " + userForm.get().email);
        UserAccount data = userForm.get();
        return ok("ok, I received POST data. That's all...");
    }
}

Or if i do this on my View/Template

<pre>@form.errorsAsJson.toString()</pre>

It works, and errors are printed accordingly. Do anyone know what i am missing here?

EDIT #2:

The best thing that works for me to output the error is by doing this on my View/Template

@(form: Form[UserAccount])

@if(form.hasErrors) {
    <h1>Please fix the following error first</h1>

    <ul>
    @for(error <- form.errors) {
        <li>@error.toString</li>
    }
    </ul>
}

Which outputs this:

(email,[ValidationError(email,error.required,[])])
(hash,[ValidationError(hash,error.required,[])])

Since I am trying to display an appropriate message to user, the message is rather useless.

Was it helpful?

Solution

After looking deeper at your code, there are two things to note:

  1. In your template you need to use the helper tags for your form fields. The helpers will display field specific errors for you: http://www.playframework.com/documentation/2.2.x/JavaFormHelpers

  2. I don't think your form has any global errors, which is why that code isn't displaying anything.

Try the helpers and see if that works for you.

OTHER TIPS

You can use the flash scope:

Controller:

public Result create(){
   flash("error", "error msg");
   return badRequest(view.render());
}

View:

@flash.get("error")

The problem is that your form doesn't have "global errors", it has errors for the fields email and hash. It's different.

You can check the error for the fields using:

@if(form.error("email") != null) { }

And you can fire global error as belor on controller:

form.reject("global error");

More info: http://www.playframework.com/documentation/2.0/JavaSessionFlash

I need to see your full template, controller, and routes file. I think the problem is that you don't have a method signature at the top of your template file, something like this:

@(userForm: Form[User])

Once you fix the template, you have another problem that you are not passing the form to the view template in the "badRequest()" flow. Try changing your controller action to look like this:

public static Result createAccount(){
    Form<UserAccount> userForm = form(UserAccount.class).bindFromRequest();
    if(userForm.hasErrors()){
        return badRequest(views.html.createUserTemplate.render(userForm));
    }else{
        UserAccount.create(userForm.get());
        Logger.info("Username is: " + userForm.get().email);
        return ok("ok, I recived POST data. That's all...");
    }
}

Your global errors code is mostly correct, it should look like this:

@if(userForm.hasGlobalErrors) {
  <ul>
  @for(error <- userForm.globalErrors) {
    <li>@error.message</li>
  }
  </ul>
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top