播放验证 - 具有特定字段错误的自定义表单字段验证
问题描述:
case class Address(
address1: String,
city: String,
state: String,
postal: String,
country: String
)
Form(
mapping = mapping(
"address1" -> nonEmptyText,
"city" -> nonEmptyText,
"state" -> nonEmptyText,
"postal" -> nonEmptyText,
"country" -> nonEmptyText
)(Address.apply)(Address.unapply).verifying("Invalid Postal Code!", validatePostal _)
)
def validatePostal(address: Address): Boolean = {
address.country match {
case "US" | "CA" =>
val regex: Regex = ("^(\\d{5}-\\d{4}|\\d{5}|\\d{9})$|^([a-zA-Z]\\d[a-zA-Z]()?\\d[a-zA-Z]\\d)$").r
regex.pattern.matcher(address.postal).matches()
case _ => false
}
}
以上表单验证的邮政编码工作正常,表单上显示无效美国或加拿大邮政编码的全局错误。播放验证 - 具有特定字段错误的自定义表单字段验证
我想显示错误作为字段错误在字段旁边,而不是全局错误,在我的情况是显示在窗体的顶部。
有没有一种方法可以使用内置的Form约束或验证方法来实现这一点而不是FormError?
答
您可以将约束添加到该字段。然后更新验证邮件以接受两个值的元组。
Form(
mapping = mapping(
"address1" -> nonEmptyText,
"city" -> nonEmptyText,
"state" -> nonEmptyText,
"postal" -> tuple(
"code" -> nonEmptyText,
"country" -> nonEmptyText
).verifying("Invalid Postal Code!", validatePostal _),
)((address1, city, state, postal) => Address(address1, city, state, postal._1, postal._2))((address: Address) => Some((address.address1, address.city, address.state, (address.postal, address.country))))
)
模板:
@inputText(
addressForm("postal.code"),
'_label -> "Postal code",
'_help -> "Please enter a valid postal code.",
'_error -> addressForm.error("postal")
)
答
定义错误,就像您在窗体中创建一个FormError("","Invalid Postal Code!")
对象一样,因为它没有键(第一个参数),框架不会将错误附加到表单元素。
在形式的错误时,你要绑定的请求表,你必须创建一个新的形式取出FormError("","Invalid Postal Code!")
与FormError("form.id","message")
在我们的项目中,我们创建了一个隐含的高清的形式,以一个错误替换它替换形式的错误(我们无法找到一个方法来创建动态约束验证)这些是2点的定义,我们有:
def replaceError(key: String, newError: FormError): Form[T] = {
val updatedFormErrors = form.errors.flatMap { fe =>
if (fe.key == key) {
if (form.error(newError.key).isDefined) None
else {
if (newError.args.isEmpty) Some(FormError(newError.key,newError.message,fe.args))
else Some(newError)
}
} else {
Some(fe)
}
}
form.copy(errors = updatedFormErrors.foldLeft(Seq[FormError]()) { (z, fe) =>
if (z.groupBy(_.key).contains(fe.key)) z else z :+ fe
})
}
def replaceError(key: String, message: String, newError: FormError): Form[T] = {
def matchingError(e: FormError) = e.key == key && e.message == message
val oldError = form.errors.find(matchingError)
if (oldError.isDefined) {
val error = if (newError.args.isEmpty) FormError(newError.key,newError.message,oldError.get.args) else newError
form.copy(errors = form.errors.filterNot(e => e.key == key && e.message == message)).withError(error)
}
else form
}
我们那些在一个名为FormCryptBind
(类,因为我们还加强与表单对象一些加密的东西),我们定义像th一样的隐式def是:
implicit def formBinding[T](form: Form[T])(implicit request: Request[_]) = new FormCryptBind[T](form)
我们那样做,因为刚刚导入有这种隐含定义的对象,你可以使用所有的FormCryptBind
定义,因为他们窗体的
而且我们使用这样的
import whatever.FormImprovements._
...
object SomeController extends Controller{
...
def submit = Action{ implicit request =>
form.bindRequest.fold(
formWithErrors => {
val newForm = formWithErrors.replaceError("", "formField.required", FormError("formField", "error.required")
BadRequest(someView(newForm)
},
formDetails => Redirect(anotherView(formDetails))
}
因为我不能从应用程序中放置实际的实时代码,所以我稍微摸了一下:D因此如果您复制&粘贴
在他确认他validatePostal定义同时使用邮政和国家的价值观,所以我不认为这是一个有效的解决方案。 – Khanser
@Khanser,谢谢你指出。我改变了上面的代码来处理这种情况。 – dingdong
如果他不关心这个错误是否包含代码和contry,那么这是一个完全有效的解决方案:)也许可以使用约束来改进它http://www.playframework.com/documentation/2.2.x/ScalaCustomValidations所以,验证消息被限制在约束验证中,而不是每个使用它的表单。 – Khanser