In Play 2.4.0 How to NAME a field in a multipolar constraint on a nested form?

This is a question about complex forms: How to get the id of a child (case class) in Play Framework (2.4.0) using forms

lazy val aForm = Form(
mapping(
  "ID" -> ignored(id),
  "firstName" -> nonEmptyText,
  "lastName" -> nonEmptyText,
  "listOfEmails" -> mapping(
     "ID" -> ignored(emailID),
     "email" -> email,
     "userID" -> ignored(id),
     "emailTypeID" -> longNumber)
     (UserEmail.apply)(UserEmail.unapply) verifying someConstraint,
  "statusID" -> ignored(0l),
  "roleID" -> default(longNumber, roleID),
  "timezoneID" -> default(longNumber, timezoneID) 
  (User.apply) 
  (User.unapply)
  )

      

Now, since the constraint after the method apply

has transformed case class

and access to all of its fields, and as such, we can write a validation that uses data from any and all fields. Not sure if I'm really happy with this - why convert the data before testing - why can't we just use the data we already have for the validation process? It also presents a problem if it itself case class

has any exceptions in creation due to erroneous data or internal validation processes, but it would be a small enough corner case to create a workflow for - a custom case class

validation only.

   def someConstraint: Constraint[UserEmail] =  Constraint("constraints.unique")({
     userEmail =>
          match doStuff(userEmail.ID, userEmail.email, userEmail. emailTypeID) {
          case BAD => Invalid(Seq(ValidationError("error.unique.email.required")))
          case GOOD => Valid
          }
       }
    |)

      

Sorry for the pseudocode, but hopefully you get a basic idea of ​​what happens during the validation process. We take several fields and process the data they contain to make a validation request.

Here's the thing though.

At the output of HTML nested class field must be marked as listOfEmails[x].ID

and listOfEmails[x].email

etc to playback structure them correctly recorded on the page POST

- https://www.playframework.com/documentation/2.4.0/ScalaForms

However, the Constraint process returns listOfEmails[x]

as the field name for the error key and as such it will not show up in the html template as that key does not match anything.

So how can you rename the key of the error field (assuming that's the correct answer here), or perhaps the more important questions - how to make this process a gameplay permanently?

Yes, we can use global errors, however, in a large and complex form, we want to get the error as close as possible to the solution for the user's eyeballs in order to quickly get up and move forward.

+3


source to share


1 answer


object TestSeq extends App {
//case class Email(email: String)
  case class Email(email: String,f1:String,f2:String,f3:String,f4:String,f5:String,f6:String,f7:String,f8:String,f9:String)
  case class User(name: String, emails: Seq[Email], addr: String)

  import play.api.data.Forms._
  import play.api.data._
  import play.api.data.validation._

  val someConstraint: Constraint[Email] =
    Constraint("constraints.unique"){  email =>
      if(email.email.contains('@')) Valid
      else Invalid(ValidationError("error.unique.email.required"))
    }

  val form = Form(
    mapping(
      "name" -> text,
      "emails" -> seq(mapping(
        "email" -> nonEmptyText,
        "f1" -> text,
        "f2" -> text,
        "f3" -> text,
        "f4" -> text,
        "f5" -> text,
        "f6" -> text,
        "f7" -> text,
        "f8" -> text,
        "f9" -> text
      )(Email.apply)(Email.unapply) verifying someConstraint),
      "addr" -> text
    )(User.apply)(User.unapply)
  )

  val data = Map[String, String](
    "name" -> "xx",
    "emails[0].email" -> "a0@xx.com",
    "emails[0].f1" -> "0f1",
    "emails[0].f2" -> "0f2",
    "emails[0].f3" -> "0f3",
    "emails[0].f4" -> "0f4",
    "emails[0].f5" -> "0f5",
    "emails[0].f6" -> "0f6",
    "emails[0].f7" -> "0f7",
    "emails[0].f8" -> "0f8",
//    "emails[0].f9" -> "0f9",
    "emails[1].email" -> "",
    "emails[1].f1" -> "1f1",
    "emails[1].f2" -> "1f2",
    "emails[1].f3" -> "1f3",
    "emails[1].f4" -> "1f4",
    "emails[1].f5" -> "1f5",
    "emails[1].f6" -> "1f6",
    "emails[1].f7" -> "1f7",
    "emails[1].f8" -> "1f8",
    "emails[1].f9" -> "1f9",
    "emails[2].email" -> "a2xx.com",
    "emails[2].f1" -> "2f1",
    "emails[2].f2" -> "2f2",
    "emails[2].f3" -> "2f3",
    "emails[2].f4" -> "2f4",
    "emails[2].f5" -> "2f5",
    "emails[2].f6" -> "2f6",
    "emails[2].f7" -> "2f7",
    "emails[2].f8" -> "2f8",
    "emails[2].f9" -> "2f9",
    "addr" -> "dalian"
  )

  val user = form.bind(data).fold(
    ef => ef.errors.foreach(println _) ,
    contact =>println(contact)
  )

  /* ===== output =====
  FormError(emails[0].f9,List(error.required),List())
  FormError(emails[1].email,List(error.required),WrappedArray())
  FormError(emails[2],List(error.unique.email.required),WrappedArray())
  user: Unit = ()
  */
}

      



0


source







All Articles