Search code examples
javajpaplayframeworkplayframework-2.2

Play Framework: Bind from request returns 'null'


I've created an edit view for my model 'Elk', but when I click submit, I only get 'null'.

In 'editElk' I prefill the form with data from the database. This data is rendering correctly in the view. The error occurs when I click 'submit'. I've commented the line giving me 'No value'. I've followed the computer-database-jpa sample, but I just cant understand why my form is returning 'no value'.

This is my controller:

import play.data.*;
import static play.data.Form.*;

@Transactional(readOnly = true)
public static Result editElk(Long id) {
    Form<Elk> editElkForm = form(Elk.class).fill(Elk.findById(id));
    return ok(views.html.tableio.editelk.render("Edit Elg", editElkForm));
}

@Transactional
public static Result submitEditedElk() {
    Form<Elk> submittedForm = form(Elk.class).bindFromRequest();
    submittedForm.get().toTableData(); // Gives: IllegalStateException: No value] 
    if (submittedForm.hasErrors()) {
        return ok(views.html.tableio.editelk.render("Edit Elg - Error",
                submittedForm));
    } else {
        submittedForm.get().update(submittedForm.get().getId());
        return TODO;

    }
}

And this is my editElk view:

@(title: String, elkForm: Form[Elk])
@import helper._
@main(title){

<h5>Edit</h5>

@form(action = routes.TableIO.submitEditedElk()) { 
@inputText(elkForm("area"))
@inputText(elkForm("sex"))
@inputDate(elkForm("date"))
@inputText(elkForm("weigth"))
@inputText(elkForm("veal"))
@inputText(elkForm("antlers"))
@inputText(elkForm("age"))
@inputText(elkForm("twin"))
@inputText(elkForm("sumTick"))
@inputText(elkForm("sumLice"))

<button type="submit">Save</button>
  }

}

And finally my routes file:

GET     /editelk/:elkid             controllers.TableIO.editElk()
POST    /submitEditedElk            controllers.TableIO.submitEditedElk()

Edit As requested, added the Elk class.

@Entity
public class Elk {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long            id;

@Required
private Date            date;

@Required
private int             weight;

@Required
private double          age;

@Required
private int             antlers;

@Required
private int             veal;

@Required
private int             twin;

@Required
@ManyToOne
private Tick            sumTick;

@Required
@ManyToOne
private DeerLice        sumLice;

@Required
@ManyToOne
private Sex             sex;

@Required
@ManyToOne
private Area            area;

@Required
@ManyToOne
private HuntingField    huntingfield;

public static Elk findById(Long id) {
    return JPA.em().find(Elk.class, id);
}

@Transactional
public void save() {
    this.sumTick = Tick.findById(sumTick.id);
    this.sumLice = DeerLice.findById(sumLice.id);
    this.sex = Sex.findById(sex.id);
    JPA.em().persist(this);
}
}

I have omitted the getters and setters.


Solution

  • Your first issue might be the typo you have in your weight input field:

    @inputText(elkForm("weigth")) // Should be @inputText(elkForm("weight"))
    

    With this typo, when you submit a form there won't be a weight key in the body of your HTTP POST request. Consequently, when you bind the POST data to a form object in the following statement:

    Form<Elk> submittedForm = form(Elk.class).bindFromRequest();
    

    The weight attribute of the wrapped Elk will be zero. Your form will therefore be considered invalid because weight is a required value.

    To clarify, the IllegalStateException you're getting isn't because there's a bug in your view or model code. It is because you're trying to unwrap a form object that contains validation errors. As the documentation and samples illustrate, you should only call the get() method on a form after you've called .hasErrors() and it has returned false.

    After correcting this typo, I'd probably have a look at what's getting sent for your non-primitive fields (sumTick, sumLice, sex, area, huntingField). I'm going to go ahead and assume that the associated types in your model class are enums. If this is the case, you should check that the values being submitted are names of corresponding enum values (in which case the binding will produce a valid form).

    Update

    Your date field skipped my attention. If you're submitting dates in a yyyy-MM-dd format, add the following annotation to the date attribute on your model class.

    @Required
    @Formats.DateTime(pattern="yyyy-MM-dd")
    private Date date;
    

    This is the approach taken in the sample projects. With this annotation Play will populate the Date field in your form object with the date String from the POST submission.