可変長のフォームに対応する
まぁ特に難しい話はなし。
リピートしたい類のモデルを用意する。
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 かねぇ?