playframeworkplay-bootstrap

PlayFramework java and that play ~ bootstrap helper


can someone give me an example of a simple form that, when given a simple object, you can hit save and know that it has all the data needed to save the object (including the id?)

Using the playfound here

(This is just a placeholder so i can post the answer - why does nobody like giving examples that work in their frameworks? Sigh)


Solution

  • That was less obvious that I wanted - I'm from the school where you "hide" the id in the form, in some sort of hidden field or somesuch.

    Maybe the play-bootstrap codebase has some nifty way of doing that, but I didn't see it in the documentation - so here, my friend, is how to take some object, make a form for it and then be able to update that objext.

    I've left the db code out, for conciseness.

    First up, here is my action - in my controller class - that gets my model from the database. Note that the backing model i am using is the same as the database returns, with private fields etc. (So, you know, just a generic POJO).

    public Result editLesson(int languageId){
        Form<Language> languageForm = formFactory.form(Language.class);
    
        try {
            //here da is just how i get things from the database.
            Language language = da.getLanguage(languageId);
            languageForm = languageForm.fill(language);
        } catch (SQLException e){ //SAD! } 
        return ok(editLesson.render(languageForm));
    }
    

    Neat. So that just gets the form and whiffs it off to some page to see. Note that formFactory needs to be magically injected into your controller. Next, what does the page look like?

    Well, it is a usual template, only:

    I have this as my first line: @import b3.vertical.fieldConstructor

    and where i want to show the form i have

    @b3.form(routes.HomeController.saveLesson) {
        @b3.hidden( "id", languageForm("id").value, 'attr -> false )
        @b3.text( languageForm("name"), '_label -> "Title", 'placeholder -> "The Title" )
        @b3.text( languageForm("description"), '_label -> "Description", 'placeholder -> "The Description" )
        @b3.submit('class -> "btn btn-default"){ <span class="glyphicon glyphicon-ok"></span> Save }
    }
    

    Ok, so here we have the form - this tells the form where to go (we'll look at the routes in 5 seconds), and puts up the editable fields. I set the id field to hidden here. It wasn't intuitive to me how to access it - but there you are.

    My routes file has this:

    GET     /edit-lesson/:languageId    controllers.HomeController.editLesson(languageId: Integer)
    POST    /save-lesson/               controllers.HomeController.saveLesson()
    

    The first line is how i start editing pages. The second line is where i want to go to save these edited lessons. I use the routes.HomeController.saveLesson to reverse-point to the save-lesson. If your controller is called Bob (dumb name), you'd instead use routes.Bob.saveLesson to link to the saveLesson method.

    Finally, my saveLesson code looks like this (in Bob ~ erm, HomeController)

    public Result saveLesson(){
        Form<Language> languageForm = formFactory.form(Language.class).bindFromRequest();
    
        if (languageForm.hasErrors()){
            return badRequest(editLesson.render(languageForm));
        } else {
            Language language = languageForm.get();
            try {
                da.saveLanguage(language);
                return ok(share.render());
            } catch (SQLException e){
                //TODO: log this, but really we don't have much to do, do we?
                return ok(e.getMessage());
            }
        }
    }
    

    Note data binding is messed up in Play - if your form has errors, the call .get() WILL fail, so in case in your controller you want some of the form data for some reason, you need to check if the form has an error - if it doesn't, do whatever. If it does, you need to use .field(String).value() on the form object, you cannot convert the form object to the binding (via get()) ~ this is exlpained somewhat on the scala page, but not on the java page!