例えば、こんなFORM
これを実装するには、けっこう手間がかかります。
JavaScriptのonclickイベントで、actionやhiddenパラメータを書き換えたりするのが常套手段(いつものことながらメンドクサイ)と思いますが、Liftはちょっと賢い。
■View
<lift:requestView.acceptForm form="post">
申請者: <f:user/>
内容: <f:body />
<f:accept />
<f:reject />
</lift:requestView.acceptForm>
■Snippet
class RequestView {
object id extends RequestVar[Long](S.param("id").map(_.toLong).openOr(0L))
def acceptForm(xhtml:NodeSeq):NodeSeq = Request.find(id) match {
case Full(r) =>
bind( "f", xhtml,
"user" -> Text(r.user),
"body" -> Text(r.body),
"accept" -> SHtml.submit("承認", doAccept),
"reject" -> SHtml.submit("否認", doReject) )
case _ => NodeSeq.Empty
}
private def doAccept(){
Request.find(id).open_!.accept
}
private def doReject(){
Request.find(id).open_!.reject
}
}
押されたボタンに応じて、doAccept/doRejectが反応します。
生成されたHTMLを除いてみると、
<form action="/request/24" method="post">
申請者: xxxxx
内容: xxxxxxx
<input name="F1215568953217KTV" type="submit" value="承認" />
<input name="F1234793613837213" type="submit" value="否認" />
</form>
こんな風に、Submitボタンのnameをキーにして、押されたボタンとサーバサイド関数が対応付けられているようです。
Liftはinputタグのnameは、全てLiftが自動付与するようになっているので注意(そうではない"普通のやり方"もやればできますが)。
こういったイベントとサーバサイドコールバックを紐付ける機能は、WicketやClick Frameworkにも導入されていますが、ActionListenerやアノテーションではなく、"関数"である点がLift+Scalaのメリット。コードが短く自然に書けます。
関数型言語であることをちょっと活かして、
複数行のFORMを考えてみます
例えばこんなFORM。
ボタン周辺に小さいFORMを何個も作るか、ボタンを押すたびにJavaScriptコールするか、といったところでしょうか。熟練者ほどパッと見でうんざりするFORM、「またか・・」と。
でも、Liftなら大丈夫!
■View
<table>
<tr>
<th>申請者</th><th>内容</th>
<th></th>
</tr>
<lift:requestView.listForm form="post">
<tr>
<td><f:user /></td><td><f:body /></td>
<td><f:accept />/<f:reject /></td>
</tr>
</lift:freemarketView.requests>
</table>
■Snippet
class RequestView {
def listForm(xhtml:NodeSeq) = Request.findAll.flatMap( r => {
bind("f", xhtml,
"user" -> Text( r.user ),
"body" -> Text( r.body ),
"accept" -> SHtml.submit("承認", doAccept(r.id) ),
"reject" -> SHtml.submit("否認", doReject(r.id) ) )
})
private def doAccept(id:Long)(){
Request.find(id).open_!.accept
}
private def doReject(id:Long)(){
Request.find(id).open_!.reject
}
}
ポイントはカリー化を使って各Request.id毎にdoAccept/doReject関数を生成してやるところ。
※但し、使うかどうかもわからないイベントリスナーをたくさん生成するのは、どうなの?という考察は必要かなとは思います。
SHtml.submitが持つ「イベントと関数のバインディング」のおかげで、複雑なFORMでも割と簡単に短いコードで、しかも(ここ重要)サーバサイドのコーディングだけで対応できます。
サーバサイドのことを考えつつJavaScriptを弄って・・などという有りがちな煩雑さがなくなって、良い感じ。Ajaxを含め、Liftにはこういう観点の機能が豊富です。