Forms rendering in Play Framework

on waitingforcode.com

Forms rendering in Play Framework

Previous article presented forms and validation in Play Framework. But we didn't described how to display and format forms in the templates.

This time we'll do it. At the begin we'll show how to display simple forms. After that, we'll focus on more customized presentation.

Display forms in Play Framework templates

Forms can be rendered thanks to form helpers. All helpers are located in Scala's package called view/helper and they are represented by .scala.html files. So, if you want to create a form, we need to use @form helper which content looks like:

@(action: play.api.mvc.Call, args: (Symbol,String)*)(body: => Html) 

@body

Two other useful elements in the case of our register form are helpers to generate text and password inputs:

@(field: play.api.data.Field, args: (Symbol,Any)*)(implicit handler: FieldConstructor, lang: play.api.i18n.Lang)

@inputType = @{ args.toMap.get('type).map(_.toString).getOrElse("text") }

@input(field, args.filter(_._1 != 'type):_*) { (id, name, value, htmlArgs) =>
    
}

and

@(field: play.api.data.Field, args: (Symbol,Any)*)(implicit handler: FieldConstructor, lang: play.api.i18n.Lang)

@input(field, args:_*) { (id, name, value, htmlArgs) =>
    
}

To construct form and its fields, we need to use information about created play.data.Form instance (User in our case). We can also specify supplementary HTML attributes, directly after the field object:

@helper.form(action = routes.UserController.registerSubmit()) {
    	@helper.inputText(userForm("login"), 'id -> "userLogin", 'fieldImportancy -> "VERY-HIGH", 'size -> 10)
    	@helper.inputPassword(userForm("password"))
    	@helper.inputText(userForm("birthday"))
    	
}

This code should generate following HTML:

Required
Maximum length: 10
constraint.pattern
Minimum length: 5
Required
BeforeDate

Customize forms view in Play Framework

As you could see, generation of form HTML is quite simple. But it may be not adapted to your expectations. It's why Play Framework allows also some of customization. In our case, we want to override inputs creation to not show

tags. To make it possible, we need to create a field constructor that takes all element information (validation errors, field data) and put them together inside one template. We'll make this construct in views/form/helpers directory:

@(elements: helper.FieldElements)

@elements.input

@elements.errors.mkString(", ")

The name of this file will be inputFieldHelper.scala.html. Now we can come back to our register.scala.html and import new form field constructor:

@(userForm: play.data.Form[User])
@import helper._

@implicitField = @{FieldConstructor(helpers.form.inputFieldHelper.render)}

@main("Welcome to register page") { 
	@helper.form(action = routes.UserController.registerSubmit()) {
    	@helper.inputText(userForm("login"), '_label -> "Login", 'id -> "userLogin", 'fieldImportancy -> "VERY-HIGH", 'size -> 10)
    	@helper.inputPassword(userForm("password"), '_label -> "Password")
    	@helper.inputText(userForm("birthday"), '_label -> "Birthday")
    	
	}
}

As you can see, they're some new things. The first is the import of all members of helper._ package. Thanks to it, we can retrieve FieldConstructor. After that, we override default constructor by the constructor of our template. Now, all fields will be generated with it. In additionally, we added some of improvements for the form, as label customization (note that they have to be named _label, otherwise they would be considered as HTML field attributes). After the compilation and execution of the page, we should receive the register form based on our inputFieldHelper template:

In this article we could see how to generate the view of forms. The first part covered a standard Play method. But because generated forms weren't adapted to our expectaitions, we needed to override this behaviour with new default field constructor. This technic was presented in the second part of the article.

Share on: