Search code examples
scalaplayframework-2.2

Play Framework 2 field grouping


I have a "group" of the following inputs:

  • text input 1
  • text input 2
  • checkbox

Text input 1 is always required. Text input 2 is only required if the checkbox is checked. How can I achieve this type of validation with play? Currently I have something like this:

val myForm: Form[MyData] = Form(
  mapping(
    "text1" -> text.verifying("Text1 is required", !_isEmpty),
    "text2" -> text.verifying("Text2 is required", !_isEmpty),
    "check" -> boolean
)

But clearly this is not what I want since it will always require text2. Is there a way to compose this to achieve this interdependent validation?

update based on wheaties suggestion: This solution worked, however it has some quirks that I need to overcome:

  1. The ad-hoc validation doesn't occur until all of the other constraints in the form pass. If the other constraints fail, the ad-hoc validation doesn't even execute. I need them all to execute together so I can show all the error messages on the form.
  2. The error that gets assigned during this ad-hoc validation does not apply to the specific form input, e.g. text2. In my template, I need to show an error message on text2 saying something like ("since you checked the checkbox, you need to fill out this input"). Rather, the error is just a general "form-level" error. You can imagine I'll have multiple instances of this type of validation so I can just assume that this error applies to text2.

I looked at the custom validators the play supports, but I do not see how I can use them to operate across multiple fields. The example they show applies only the the form field that is being validated with no obvious way to reference other inputs in the form.


Solution

  • You can see from the documentation that they allow for ad-hoc validations on the form objects you create (see documents.) What you can do is make a validator:

     def validate(text1: String, text2: String, check: Boolean) = if(check) text2.nonEmpty else true
    
     val myForm: Form[MyData](
       mapping("text1" -> text.verifying("Text1 is required", !_isEmpty))
     )(MyData.unapply)(MyData.apply) verifying ("Text2 is required if check box checked", {
       case data => validate(data.text2, data.check)
     })
    

    which should give you what you want but I'd also check out their custom validators section as well (since they recommend this as a good route to follow.)