Playframework 2渲染二维形式

时间:2014-07-25 02:56:20

标签: forms playframework-2.0 template-engine

我有一个重复值的表单:

val editPropertiesForm = Form(
    single(
      "prop" -> seq(
        tuple(
          "color_id" -> longNumber,
          "size_id" -> longNumber,
          "quantity" -> longNumber
        )
      )
    )
  )

下一步该怎么做?如何渲染表:

         size1  size2  ...  sizeN

color1    q1_1   q1_2  ...  q1_N

color2    q2_1   q2_2  ...  q2_N

...       ...    ...   ...  ...

colorM    qM_1   qM_2  ...  qM_N

我无法理解如何对表单的值进行分组并渲染它们。

2 个答案:

答案 0 :(得分:0)

首先创建一个动作,根据需要填充表单数据并将其传递给视图。

def showForm = Action { implicit request =>
  val sampleData = Seq((11L, 12L, 13L), (21L, 22L, 23L))
  val form = editPropertiesForm.fill(sampleData)
  Ok(views.html.form(form))
}

视图可以使用帮助器 repeat()方法迭代表单seq。

@(propForm: Form[Seq[(Long, Long, Long)]])(implicit request: RequestHeader)

@import helper._

<form action="@routes.FormController.handleForm()" method="post">
@helper.repeat(propForm("prop")) { row =>
    <input id="@row("color_id").id" name="@row("color_id").name" value="@row("color_id").value">
    <input id="@row("size_id").id" name="@row("size_id").name" value="@row("size_id").value">
    <input id="@row("quantity").id" name="@row("quantity").name" value="@row("quantity").value">
    <br>
}
<input type="submit" value="Send">
</form>

您应该考虑使用custom field constructors来保持视图清洁。

最后在第二个动作中处理表单。

def handleForm = Action { implicit request =>
  editPropertiesForm.bindFromRequest.fold(
    formWithErrors => BadRequest(views.html.form(formWithErrors)),
    prop => {
      prop.foreach { row =>
        val colorId = row._1
        val sizeId = row._2
        val quantity = row._3
      }
      Ok(prop.toString())
    }
  )
}

使用普通的case类替换表单元组也可以提高代码的可读性。

答案 1 :(得分:0)

我使用rowHeader和columnHeader列表,其中包含渲染头的名称和ID。

表格

val editOrderForm = Form(
  single(
    "order" -> list(
      tuple(
        "size_id" -> longNumber,
        "color_id" -> longNumber,
        "quantity" -> optional(longNumber)
      )
    )
  )
)

转换表格的助手

@tableModel(formForTableModel: Form[scala.List[(Long, Long, Option[Long])]]) = @{
    formForTableModel("order").indexes
        .map { ind =>
            val fieldNamePrefix = s"order[$ind]"
            val a = (formForTableModel(fieldNamePrefix + ".size_id").value, formForTableModel(fieldNamePrefix + ".color_id").value) match {
                case (Some(sizeId), Some(colorId)) =>
                    Some((sizeId.toLong, colorId.toLong))
                case _ =>
                    None
            }
            a.map(p=> (p._1, p._2, formForTableModel(fieldNamePrefix)))

        }
        .filter(f=> f.isDefined)
        .flatten
}

简单助手输入HTML输入

@constr1(elements: FieldElements) = {
    @elements.input
}

使用二维数据渲染表

<form action="@routes.xxx" method="post" data-product-id="@productId">
    @defining(tableModel(orderForm)) {model =>
        <table class="order-table table table-bordered table-condensed table-responsive">
            <tr>
                <td></td>
                @columnHeaders.map{columnHeader =>
                    <td>@columnHeader._2</td>
                }
                </tr>
            @rowHeaders.map{rowHeader =>
                <tr>
                    <td>@rowHeader._2</td>
                    @columnHeaders.map{columnHeader =>
                        @model.find(f => f._1==columnHeader._1 && f._2==rowHeader._1).map(_._3).fold{
                            <td class="order-cell blocked"></td>
                        }{field =>
                            <td class="order-cell @state(field("quantity"))">
                                @inputText(field("size_id"), 'type -> "hidden")(FieldConstructor(constr1), lang)
                                @inputText(field("color_id"), 'type -> "hidden")(FieldConstructor(constr1), lang)
                                @inputText(field("quantity"), 'type -> "number", 'autocomplete -> "off", 'min -> "0", 'maxlength -> "3", 'size->"3")(FieldConstructor(constr1), lang)
                            </td>

                        }
                    }
                </tr>
            }
        </table>
    }
    <div class="actions">
        <input type="submit" value="Save" class="btn btn-primary">
        <a class="btn btn-default cancel" href="@routes.ReservationController.showReservation(reservationId)">Cancel</a>
    </div>
</form>