Scala Play:如何使用重复值和嵌套值呈现表单映射?

Posted

技术标签:

【中文标题】Scala Play:如何使用重复值和嵌套值呈现表单映射?【英文标题】:Scala Play: How to render Form mappings with Repeated and Nested values? 【发布时间】:2019-05-22 23:26:28 【问题描述】:

我正在开发 Scala Play 2.7.x(您可以在此处查看项目play-silhouette-seed googleauth branch),并且我的表单定义为:

object TotpSetupForm 
  val form = Form(
    mapping(
      "sharedKey" -> nonEmptyText,
      "scratchCodes" -> seq(mapping(
        "hasher" -> nonEmptyText,
        "password" -> nonEmptyText,
        "salt" -> optional(nonEmptyText)
      )(PasswordInfo.apply)(PasswordInfo.unapply)),
      "scratchCodesPlain" -> optional(seq(nonEmptyText)),
      "verificationCode" -> nonEmptyText(minLength = 6, maxLength = 6)
    )(Data.apply)(Data.unapply)
  )

  case class Data(
    sharedKey: String,
    scratchCodes: Seq[PasswordInfo],
    scratchCodesPlain: Option[Seq[String]],
    verificationCode: String = "")

其中PasswordInfo 来自Play-Silhouette,看起来像:

case class PasswordInfo(
  hasher: String,
  password: String,
  salt: Option[String] = None
) extends AuthInfo    

在我的控制器中,我填充表单并将其作为参数传递给我的视图模板,如下所示。请注意,我已经对其进行了调试,totpInfo.scratchCodes 有 5 个值,并且表单已正确填充:

val formData = TotpSetupForm.form.fill(TotpSetupForm.Data(totpInfo.sharedKey, totpInfo.scratchCodes, totpInfo.scratchCodesPlain))
Ok(views.html.someView(formData, ...)

我将视图渲染如下,请注意我确实阅读了the Scala Forms Repeated Values documentation note :)

@helper.form(action = controllers.routes.TotpController.submit()) 
    @helper.CSRF.formField
    @b3.text(totpForm("verificationCode"), '_hiddenLabel -> messages("verificationCode"), 'placeholder -> messages("verificationCode"), 'autocomplete -> "off", 'class -> "form-control input-lg")
    @b3.hidden(totpForm("sharedKey"))
    @helper.repeatWithIndex(totpForm("scratchCodes"), min = 1)  (scratchCodeField, index) =>
        @b3.hidden(scratchCodeField, '_label -> ("scratchCode #" + index))
    
    <div class="form-group">
        <div>
            <button id="submit" type="submit" value="submit" class="btn btn-lg btn-primary btn-block">@messages("verify")</button>
        </div>
    </div>

即使正确填充了表单的 scratchCodes 序列,每个序列值仍呈现为空:

<input type="hidden" name="scratchCodes[0]" value="" >
<input type="hidden" name="scratchCodes[1]" value="" >
<input type="hidden" name="scratchCodes[2]" value="" >
<input type="hidden" name="scratchCodes[3]" value="" >
<input type="hidden" name="scratchCodes[4]" value="" >

序列中的字段数是正确的。

我也尝试过使用@helper.repeat 替代方法,甚至使用@helper.input 而不是@b3.hidden 只是为了确保结果始终相同......我得到空值PasswordInfo 渲染的元组。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

OK 找到了罪魁祸首:重复 + 嵌套值需要像这样单独访问每个属性:

@helper.repeat(totpForm("scratchCodes"), min = 1)  scratchCodeField =>
  @b3.hidden(scratchCodeField("hasher"))
  @b3.hidden(scratchCodeField("password"))
  @b3.hidden(scratchCodeField("salt"))

然后工作正常,发布请求正确填充PasswordInfo UDT 的序列。

【讨论】:

以上是关于Scala Play:如何使用重复值和嵌套值呈现表单映射?的主要内容,如果未能解决你的问题,请参考以下文章

Scala Play Json JSResultException错误API

如何使用`flatMap`和`map`填充Play框架+ Scala上的`list`?

在 Scala Play 框架中映射 OneToMany 不向第二个表插入数据

如何使用scala Play2.6从数据库中选择单列

如何访问存储在scala spark中的数据框中的映射值和键

玩!框架 CRUD 模块:添加默认值和更改日期格式?