LiftのSubmitかしこい

Liftでは、FORM内に複数のSubmitボタンを持つことができます。イベントと関数の紐付け機能は、Lift+Scalaの魅力だと思うのですがどうでしょうか。

例えば、こんなFORM

申請者: xxxx
申請内容:xxxxxxx

これを実装するには、けっこう手間がかかります。
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が自動付与するようになっているので注意(そうではない"普通のやり方"もやればできますが)。

こういったイベントとサーバサイドコールバックを紐付ける機能は、WicketClick Frameworkにも導入されていますが、ActionListenerやアノテーションではなく、"関数"である点がLift+Scalaのメリット。コードが短く自然に書けます。

関数型言語であることをちょっと活かして、

複数行のFORMを考えてみます

例えばこんなFORM。

申請者内容
user1xxxxxxxxxx
user2xxxxxxxxxx
user3xxxxxxxxxx

ボタン周辺に小さい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にはこういう観点の機能が豊富です。


同じカテゴリのエントリ
1.Lift再入門 / 8.javascriptからsubmitできない / 7.Ajax Form / 6.Radio、Checkboxについて / 5.行列型の編集FORM / 4.サーバーサイドバリデーションとサーバサイド関数 / 3.ログインFORM - S.param使ったら負け / 2.Snippetメソッドとして許される型 / sbt0.12.xで依存jar抽出タスク / scala2.10+lift2.5+NetBeans7.2 / Scalaで入門関数プログラミング / reactive-webを試してみました / Lift2.2M1のテンプレート機能 / Scala Compiler Plugin / View Bound/Context Bound / ScalaZa01参加してきました / Akka Frameworkチュートリアルの次 / Akka Frameworkチュートリアルその2 / Akka Frameworkチュートリアル / LiftでJCaptcha / Url Rewrite Filter / sbt-android-plugin / Android SDK for Scala / 祝Lift2.0リリース / Liftの携帯対応まとめ / Scala2.8への移行 / Lift 2.0-scala280-SNAPSHOT/sbt0.7.1 / Scalaお絵かき環境 - Kojo / Lift+Quartzでバッチ / Scala&Liftを採用した理由 / Liftでdate_select系ヘルパーを作る / LiftでAjax / LiftのSubmitかしこい / lift-mapperのpaginateを使う / snippetをspecする / Lift Mapperを拡張する / LiftのDBをMySQLに / Liftプロジェクト環境を整える / Scala本読み比べてみました / NetBeans6.7&scala / じつはScalaはライトな言語 / Scalaバザ~ル / lift1.0所感 / specsを読む / implicit def / ScalaならNetBeansがサイコー / scala勉強会@東北がスタート / それでも俺はLiftをやるってのか / Scala&Liftセットアップ / ブログリニューアル /
コメント

コメントしてください

closed.