1

I am building a form where a user can edit some personal details (such as name, location, etc). I am using a custom built field constructor, and I have no problems with this in other places.

@form(action = routes.Persons.update(), 'class -> "well well-lg form-horizontal"){
  <fieldset>
    @inputText(updateForm("forname"), '_label -> "First name", 'class -> "form-control")
    @inputText(updateForm("surname"), '_label -> "Last name", 'class -> "form-control")
    @inputText(updateForm("email"), '_label -> "Email", 'class -> "form-control")
    @inputPassword(updateForm("passwordHash"), '_label -> "Password", 'class -> "form-control")
  </fieldset>
  <button type="submit" class="btn btn-primary">Update</button>
}

This works. I want the user to be able to edit his first name, last name and location, however, and not the email which he is registered with. I first attempted adding 'disabled -> true to the email input, but this broke the form (password, for example, was no longer pre-filled, and I get a [IllegalStateException: No value] error when the form is posted. A similar issue is discussed here, but my issue goes further. I can't simply leave the email field out of the form. The code looks like this:

@form(action = routes.Persons.update(), 'class -> "well well-lg form-horizontal"){
  <fieldset>
    @inputText(updateForm("forname"), '_label -> "First name", 'class -> "form-control")
    @inputText(updateForm("surname"), '_label -> "Last name", 'class -> "form-control")
    @inputPassword(updateForm("passwordHash"), '_label -> "Password", 'class -> "form-control")
  </fieldset>
  <button type="submit" class="btn btn-primary">Update</button>
 }

When I try this, the form is again broken and I get the same IllegaleStateException when it is posted... the problem is not, I believe, in the controller, as everything works fine as long as the email field is present...

My suspicion is that this is caused by the fact that I have a @constraint on email in the model. Can someone confirm this? And how can I bypass this, so that I can have a prefilled form which is linked to an object, but where I can edit just a some of the attributes?

Thanks for any help!

Community
  • 1
  • 1
Bischoff
  • 73
  • 5

1 Answers1

0

So, as I understand your problem, you want to allow a user to update all his details except his email address.

Assuming you want to display their email address but have it uneditable there are two options:

  1. Mark your email input as 'readonly'. This will not allow the user to change the email address and it will still be sent as part of the form post.

    @inputText(updateForm("email"), '_label -> "Email", 'class -> "form-control", 'readonly -> "readonly")
    
  2. Mark the email input as 'disabled'. This did not work for you because disabled inputs are not sent as part of the form post. See here. However, you can get around that by adding a hidden input to your form for the email address. When the form is posted, the users mail address will still be sent, which won't break your controller.

    @form(action = routes.Persons.update(), 'class -> "well well-lg form-horizontal") {
      <input type="hidden" name="email" value="@updateForm("email").value"/>
      <fieldset>
        @inputText(updateForm("forname"), '_label -> "First name", 'class -> "form-control")
        @inputText(updateForm("surname"), '_label -> "Last name", 'class -> "form-control")
        @inputText(updateForm("email"), '_label -> "Email", 'class -> "form-control", 'disabled -> "disabled")
        @inputPassword(updateForm("passwordHash"), '_label -> "Password", 'class -> "form-control")
      </fieldset>
      <button type="submit" class="btn btn-primary">Update</button>
    }
    

If you don't want to display the email address then you can use option 2 above and just remove the email input. Your controller won't break because the hidden input's value for email will be posted.

As for the reason you're getting an IllegalStateException, that's because you don't seem to be validating your form object in your controller. You are correct in that your @Constraint.xxx is causing that, however, it shouldn't get to that point if you validate your form object correctly. See below for an example:

public static Result update() {
    Form<Person> personForm = Form.form(Person.class).bindFromRequest(request());
    if(personForm.hasErrors()) {
        return badRequest(person.render(personForm));
    }

    personForm.get().save();

    return ok("Saved...");
}

note the if(personForm.hasErrors()) section. See the Play docs for more on form validation.

Community
  • 1
  • 1
Donovan Muller
  • 3,822
  • 3
  • 30
  • 54
  • Thanks, this is very helpful. I already figured out the readonly attribute, which relieved me from some of my worries. It is, however, very useful to read what you say about the @Constraint and that it doesn't have to be an issue if I validate correctly. I made things work now, but only with some moderations to what you suggested. The save() function only created a new Person (as I don't use an ID-field in the form, I store the ID as a session key). A bit cumbersome, maybe, but I ended creating a new Person according to the session and updating that one with the values from the form. Bad? – Bischoff Jun 25 '14 at 21:00
  • If I understand correctly. The only issue with storing the person's Id in the session (it's just a cookie in Play) is that if the user blocks cookies, your whole app is not going to work properly. Why not just pass the Id property though to your pages and then pass that through to your actions on form submit? I.e. `@form(action = routes.Persons.update(personId)`. [See this sample project](https://github.com/playframework/playframework/blob/2.2.x/samples/java/computer-database/app/views/editForm.scala.html) – Donovan Muller Jun 26 '14 at 07:38
  • Yeah, I can see that being an issue and I might look into that a bit down the road. If a user has blocked cookies, however, he wouldn't be able to log into the application at all, so atm I guess this is a take it or leave it scenario. How many people block cookies nowadays anyway? – Bischoff Jun 26 '14 at 11:54