Playのテンプレートでhelperを使ってHTMLフォームを出力してみる。
Play2.0.4利用。
とりあえずプロジェクト作成。
$ play new form_helper_example $ cd form_helper_example
app/views/index.scala.htmlを編集して、下記のような感じで書いてみる。
@(form: Form[Application.User])
@main("たいとる") {
@helper.form(action = routes.Application.index) {
@helper.inputText(form("name"), 'size -> 10)
@helper.inputText(form("age"), 'size -> 3)
@helper.inputRadioGroup(
form("sex"),
options = Seq("male" -> "男", "female" -> "女"),
'_label -> "sex")
<input type="submit" value="さぶみっしょん">
}
}
@helper.formでフォームを宣言して、@helper.inputTextとか@helper.inputRadioGroupなどで入力フォームを生成する。
フォームの値を受け取る項で使ったFormクラスで値を渡せば、入力された値でフォームが埋められる動きを手軽に書ける。
次にController側でFormクラスを用意してViewに渡す処理を書く。
import play.api.data.Form
import play.api.data.Forms._
case class User(name: String, age: Int, sex: String)
val form = Form(mapping("name" -> text, "age" -> number, "sex" -> text)(User.apply)(User.unapply))
def index = Action { implicit request =>
val user = form.bindFromRequest
Ok(views.html.index(user))
}
これで概ね動くようになった。エラーメッセージとかも自動出力される、それっぽいフォームが出力される。
出力されるHTMLはこんな感じ。
<form action="/" method="GET" >
<dl class=" " id="name_field">
<dt><label for="name">name</label></dt>
<dd><input type="text" id="name" name="name" value="aa" size="10"></dd>
</dl>
<dl class=" " id="age_field">
<dt><label for="age">age</label></dt>
<dd><input type="text" id="age" name="age" value="13" size="3"></dd>
<dd class="info">Numeric</dd>
</dl>
<dl class=" error" id="gender_field">
<dt><label for="gender">gender</label></dt>
<dd>
<span class="buttonset" id="gender">
<input type="radio" id="gender_male" name="gender" value="male" >
<label for="gender_male">男</label>
<input type="radio" id="gender_female" name="gender" value="female" >
<label for="gender_female">女</label>
</span>
</dd>
<dd class="error">This field is required</dd>
</dl>
<input type="submit" value="さぶみっしょん">
</form>
dl/ddで書いている。呼び出す時にclass指定してちゃんとスタイル書けばそこそこに見栄えは調整できる。
ここで使ったテキストボックスとラジオボタン以外にも、セレクトボックス、チェックボックス、テキストエリア、日付入力フィールド等、一通り用意されている。
ヘルパーは簡易なアプリを書く時は便利だけど、デザインを凝り出すと逆に面倒だったり、覚えるのに多少時間がかかる等のデメリットもある。
HTMLをベタ書きしたい場合は、こんな感じでも良いだろうか。
@(form: Form[Application.User])
@main("たいとる") {
<form action="/">
<input type="text" name="name" value="@form.data.getOrElse("name", "")"><br>
<input type="text" name="age" value="@form.data.getOrElse("age", "")"><br>
<input type="radio" name="gender" value="male" @(if(form.data.getOrElse("gender", "") == "male") "checked")>男
<input type="radio" name="gender" value="female" @(if(form.data.getOrElse("gender", "") == "female") "checked")>女
<input type="submit" value="さぶみと">
</form>
}
自前で部品書いておいてincludeしても良いかもしれない。
例えばapp/viewsにradio.scala.htmlという名前のファイルを作って、下記のように記述する。
@(name: String, value: String, formData: Map[String, String], options: Map[String, String] = Map[String, String]())
<input type="radio" name="@name" value="@value" @(if(formData.getOrElse(name, "") == value) "checked") @for( (key, value) <- options ) { @key="@value" }>
あとはこの子を呼び出せば、自前のラジオボタン用部品の出来上がり、みたいな。
<form action="/">
<input type="text" name="name" value="@form.data.getOrElse("name", "")"><br>
<input type="text" name="age" value="@form.data.getOrElse("age", "")"><br>
@radio("gender", "male", form.data, Map("class" -> "hoge")) 男
@radio("gender", "female", form.data) 女
<input type="submit" value="さぶみと">
</form>
Twitter Bootstrapを利用することもできる。helper.twitterBootstrap._をimportすれば良いようだ。
@(form: Form[Application.User]) @import helper.twitterBootstrap._ @main("たいとる") { @helper.form(action = routes.Application.index) { @helper.inputText(form("name"), 'size -> 10) 以下略
こうするとTwitter Bootstrap用のHTMLが出力される。
<form action="/" method="GET" > <div class="clearfix " id="name_field"> <label for="name">name</label> <div class="input"> <input type="text" id="name" name="name" value="aa" size="10"> <span class="help-inline"></span> <span class="help-block"></span> </div> </div> <div class="clearfix " id="age_field"> <label for="age">age</label> <div class="input"> <input type="text" id="age" name="age" value="13" size="3"> <span class="help-inline"></span> <span class="help-block">Numeric</span> </div> </div> <div class="clearfix error" id="gender_field"> <label for="gender">gender</label> <div class="input"> <span class="buttonset" id="gender"> <input type="radio" id="gender_male" name="gender" value="male" > <label for="gender_male">男</label> <input type="radio" id="gender_female" name="gender" value="female" > <label for="gender_female">女</label> </span> <span class="help-inline">This field is required</span> <span class="help-block"></span> </div> </div> <input type="submit" value="さぶみっしょん"> </form>
あとはTwitter BootStrapを落としてきて、CSSをpublic/stylesheets配下に置いて呼び出すと、表示がちょっとそれっぽくなる。