可変長のフォームに対応する
まぁ特に難しい話はなし。
リピートしたい類のモデルを用意する。
package models case class Game(name: String, vendor: String) object Game { import play.api.data._ import play.api.data.Forms._ def form = Form(maps) def multiForm = Form(single( "games" -> seq(maps) )) def maps = mapping( "name" -> nonEmptyText, "vendor" -> nonEmptyText )(apply)(unapply) }
で、これをView/Conttrollerにバインドして
package controllers import play.api.mvc._ import models.Game object Application extends Controller { def index = Action { val forms = Game.multiForm Ok(views.html.index(forms)) } def result = Action { implicit request => val forms = Game.multiForm.bindFromRequest() forms.value.foreach(games => { games.foreach(s => println(s"Game sending $s")) }) Ok(views.html.index(forms)) } }
画面はこっち
@(form: Form[Seq[Game]])
@main("Welcome to Play") {
@helper.form(routes.Application.result){
@helper.repeat(form("games"), min = 2){ field =>
@helper.inputText(field("name"))
@helper.inputText(field("vendor"))
}
<input type="submit" value="送信!"/>
}
}
routes を書いたら実行開始
# Home page GET / controllers.Application.index POST / controllers.Application.result
生成されたフォームは下記のような感じ
<form action="/" method="POST">
<dl class=" " id="games_0__name_field">
<dt><label for="games_0__name">games[0].name</label></dt>
<dd>
<input type="text" id="games_0__name" name="games[0].name" value="ICO">
</dd>
</dl>
<dl class=" " id="games_0__vendor_field">
<dt><label for="games_0__vendor">games[0].vendor</label></dt>
<dd>
<input type="text" id="games_0__vendor" name="games[0].vendor" value="Sony">
</dd>
</dl>
<dl class=" " id="games_1__name_field">
<dt><label for="games_1__name">games[1].name</label></dt>
<dd>
<input type="text" id="games_1__name" name="games[1].name" value="BioHazard">
</dd>
</dl>
<dl class=" " id="games_1__vendor_field">
<dt><label for="games_1__vendor">games[1].vendor</label></dt>
<dd>
<input type="text" id="games_1__vendor" name="games[1].vendor" value="Capcom">
</dd>
</dl>
<input type="submit" value="送信!">
</form>
id の命名規則が「(parent forms field name)(index)__(child forms field name)field」らしい。
name 属性が「(parent form field name)[(index)].(child form field name)」ということか。
ということで、手動でフォームを追加しちゃおう。
@(form: Form[Seq[Game]])
@main("Welcome to Play") {
@helper.form(routes.Application.result){
@helper.repeat(form("games"), min = 2){ field =>
@helper.inputText(field("name"))
@helper.inputText(field("vendor"))
}
<dl class=" " id="games_2__name_field">
<dt><label for="games_2__name">games[2].name</label></dt>
<dd>
<input type="text" id="games_2__name" name="games[2].name" value="BioHazard">
</dd>
</dl>
<dl class=" " id="games_2__vendor_field">
<dt><label for="games_2__vendor">games[2].vendor</label></dt>
<dd>
<input type="text" id="games_2__vendor" name="games[2].vendor" value="Capcom">
</dd>
</dl>
<input type="submit" value="送信!"/>
}
}
で、コンソールを眺めると
Game sending Game(ICO,Sony) Game sending Game(BioHazard,Capcom) Game sending Game(MetalGear,KONAMI)
良さげ。
動的にフォームを追加するなら JavaScript かねぇ?