【问题标题】:How to bind an enum to a playframework form?如何将枚举绑定到 playframework 表单?
【发布时间】:2020-09-03 05:15:22
【问题描述】:

我有一个枚举形式:

object MatchFilterType extends Enumeration {
  type MatchFilterType = Value
  val gt = Value("gt")
  val lt = Value("lt")
  val eq = Value("eq")
}

尝试在我的控制器中创建表单 val:

 case class SearchRequest(mft: MatchFilterType, queryText: String, locations: List[String])

 val searchForm: Form[SearchRequest] = Form(
    mapping(
      "mft" -> ????????,
      "queryText" -> nonEmptyText,
      "locations" -> list(text)
    )(SearchRequest.apply)(SearchRequest.unapply)
  )

我在这个项目中使用 play 2.6.x。

如何将我的枚举映射到 Form val 中?

【问题讨论】:

    标签: scala playframework


    【解决方案1】:

    首先创建一个隐式Formatter,它使用枚举withName 方法,该方法接受一个字符串并将其转换为一个枚举:

    implicit def matchFilterFormat: Formatter[MatchFilterType] = new Formatter[MatchFilterType] {
    
      override def bind(key: String, data: Map[String, String]) =
        data.get(key)
            .map(MatchFilterType.withName(_))
            .toRight(Seq(FormError(key, "error.required", Nil)))
    
      override def unbind(key: String, value: MatchFilterType) = 
        Map(key -> value.toString)
    }
    

    然后使用Forms.of创建一个FieldMapping

    Form(...,
         "mft" -> Forms.of[MatchFilterType],
         ...)
    

    请记住,如果字符串不是枚举成员,MatchFilterType.withName(_) 将引发异常,因此请更新 bind 方法以根据需要处理此问题。

    【讨论】:

    • 你能解释一下为什么我必须创建这个格式化程序吗?它背后的理论:)
    • 我怎样才能使它成为可选的?
    • @Blankman 使其成为可选只需将映射包装在 optional:"mft" -> optional(Forms.of[MatchFilterType]) 中。您需要更新SearchRequest 以获取Option[MatchFilterType]。理论见playframework.com/documentation/2.6.x/…
    • 这可以概括吗?类似 E:
    • @ObjectiveTruth 见下文stackoverflow.com/a/63348335/241133
    【解决方案2】:

    更通用的方法:

    def enumerationFormatter[E <: Enumeration](enum: E): Formatter[E#Value] = new Formatter[E#Value] {
      override def bind(key: String, data: Map[String, String]): Either[Seq[FormError], E#Value] =
        data.get(key).map(s => enum.withName(s)).toRight(Seq(FormError(key, "error.required", Nil)))
      override def unbind(key: String, value: E#Value): Map[String, String] = Map(key -> value.toString)
    }
    

    然后可以像这样使用:

    object TestValues extends Enumeration {
      type TestValue = Value
      val Test: TestValue = Value
    }
    case class MyForm(testValue: TestValue)
    object MyForm {
      implicit val testValueFormatter: Formatter[TestValue] = enumerationFormatter(TestValues)
      val form = Form(mapping("testValue" -> of[TestValue])(MyForm.apply)(MyForm.unapply))
    }
    

    【讨论】:

      猜你喜欢
      • 2010-09-28
      • 1970-01-01
      • 2011-04-25
      • 1970-01-01
      • 2011-12-21
      • 2015-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多