A Play Framework data entry form example

If you’d like an example of how to create a data entry form using the Play Framework v2.6, here’s a complete example.

 

 

 

Define the routes

First, add these entries to your routes file:

GET  /posts/add   controllers.BlogPostController.add
POST /posts/save  controllers.BlogPostController.save

Create a controller

Next, create this BlogPostController in your app/controllers directory:

package controllers

import javax.inject.Inject
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import scala.collection.mutable.ArrayBuffer

case class BlogPost (
    title: String,
    category: String,
    body: String,
    tagsAsString: String,
    metaDescription: String,
    uri: String
)

class BlogPostController @Inject()(cc: MessagesControllerComponents)
extends MessagesAbstractController(cc) {

    private val logger = play.api.Logger(this.getClass)

    // simulated database
    private val blogPosts = ArrayBuffer[BlogPost]()

    val form: Form[BlogPost] = Form (
        mapping(
            "title" -> nonEmptyText,
            "category" -> nonEmptyText,
            "blogContent" -> nonEmptyText,
            "tags" -> nonEmptyText,
            "description" -> nonEmptyText,
            "uri" -> nonEmptyText
        )(BlogPost.apply)(BlogPost.unapply)
    )

    private val mainPostUrl = routes.BlogPostController.save()

    def add = Action { implicit request: MessagesRequest[AnyContent] =>
        // pass an unpopulated form to the template
        Ok(views.html.editBlogPost(form, mainPostUrl))
    }

    def save = Action { implicit request: MessagesRequest[AnyContent] =>
        val errorFunction = { formWithErrors: Form[BlogPost] =>
            logger.debug("CAME INTO errorFunction")
            // this is the bad case, where the form had validation errors.
            // show the user the form again, with the errors highlighted.
            BadRequest(views.html.editBlogPost(formWithErrors, mainPostUrl))
        }

        val successFunction = { data: BlogPost =>
            logger.debug("CAME INTO successFunction")
            // this is the SUCCESS case, where the form was successfully parsed as a BlogPost
            val blogPost = BlogPost(
                data.title,
                data.category,
                data.body,
                data.tagsAsString,
                data.metaDescription,
                data.uri
            )
            logger.debug(blogPost.toString)
            blogPosts.append(blogPost)
            Redirect(routes.BlogPostController.add()).flashing("info" -> "Blog post added (trust me)")
        }

        val formValidationResult: Form[BlogPost] = form.bindFromRequest
        formValidationResult.fold(
            errorFunction,   // sad case
            successFunction  // happy case
        )
    }

}

Notice that the controller code includes a case class to work with the form, and the definition of a Form and a form mapping, in addition to the necessary controller methods. The add and save methods in this class correspond to the routes entries of the same names.

Create the template/form

Now add this editBlogPost.scala.html file to your app/views directory:

@(form: Form[BlogPost], postUrl: Call)(implicit request: MessagesRequestHeader)

@main("Blog Post") {

    <h1>Blog Post</h1>

    @* Flash shows updates to a page *@
    @request.flash.data.map{ case (name, value) =>
        <div>@name: @value</div>
    }

    @* Global errors are not tied to any particular form field *@
    @if(form.hasGlobalErrors) {
        @form.globalErrors.map { error: FormError =>
            <div>
                Error: @error.key: @error.message
            </div>
        }
    }

    @* “'id” in these elements is the css `id` field that will be shown *@
    @helper.form(postUrl, 'id -> "blog_edit_form") {
        @helper.CSRF.formField

        @helper.inputText(form("title"), 'id -> "title", 'size -> 60)
        @helper.inputText(form("category"), 'size -> 60)
        @helper.textarea(form("blogContent"), 'rows -> 5, 'cols -> 60)
        @helper.inputText(form("tags"), 'size -> 60)
        @helper.inputText(form("description"), 'size -> 60)
        @helper.inputText(form("uri"), 'size -> 60)

        <button>Save</button>
    }

}

This code doesn’t do anything with a database, so that’s all the code you need.

What the form looks like

Now go to the http://localhost:9000/posts/add URL in your browser and you should see a new Play Framework data entry form that looks like this:

A Play Framework data entry form example

Of course that needs some CSS styling, but that’s what it looks like out of the box.

I’m not going to take the time to explain this code because the Play Framework form documentation is very good, but if you needed to see an example of a Play data entry form I hope this is helpful.

Play form input helpers

As a note to self, this is a list of Play Framework form input helpers:

@* note: other input helpers *@
form:            form element
inputText:       text input element
inputPassword:   password input element
inputDate:       date input element
inputFile:       file input element
inputRadioGroup: radio input element
select:          a select element (select/option)
textarea:        a textarea element
checkbox:        a checkbox element
input:           a generic input element (which requires explicit arguments)

See the Play Framework forms documentation for more information on input helpers, form mapping constraints, and other details.

Form resources

Here are a couple of Play Framework form resources, some of which are helpful but hard to find: