ViewとTemplateの作成
Modelができたところで、Modelを利用して検索や保存を行う画面を作成します。ViewとTemplateの詳細については「Scala+LiftフレームワークのView/Template」を参照してください。
登録されているイベントを一覧表示するTopページ
まずは、Topページです。このページでは、登録されているイベントの一覧を表示するようにします。
最初に、テンプレートを作成しましょう。src/main/webapp/index.htmlを、ダウンロードサンプルに含まれる同名のファイルと同じ内容に置き換えます。このテンプレートは、次に作成するEventSnippetのlist関数を呼び出して、イベントの一覧が出力されるようになっています。
次は、このindex.htmlから呼び出されているEventSnippetの作成です。"src/main/scala/demo/snippet"に、以下の内容でEventSnippet.scalaを作成します。
package demo.snippet
...中略...
// イベントの情報を表示するSnippet
class EventSnippet{
/** 日付フォーマット */
val formatter = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm")
formatter.setTimeZone( TimeZone.getTimeZone( "Asia/Tokyo" ))
// implicit conversionを利用して,自動的にStringとDateが変換されるように定義
implicit def date2String( d:Date ):String = formatter.format( d ) // *1 implicit def string2Date( s:String ):Date = formatter.parse( s )
// イベントの一覧を表示します。
def list(xhtml: NodeSeq): NodeSeq = { // *2
// maxで30件を検索し、bind関数で一覧を出力
Event.findAll(30) flatMap { e =>
bind( "event", xhtml,
"id" -> e.id.get, "name" -> e.name, "description" -> e.description,
"fromDate" -> date2String( e.fromDate ), "toDate" -> date2String( e.toDate ),
"place" -> e.place, "join" -> e.join, "count" -> e.count,
"save" -> SHtml.link("save/"+ e.id.get, () =>{} , Text("編集する") )
)
}
}
}
*1で、implicit conversionを利用してString型とDate型が自動的に変換されるようにしています。
*2が、index.htmlから呼び出されるlist関数です。Modelとして作成したEventオブジェクトのfindAll関数を呼び出して、一覧に表示するEvent情報をListで取得し、bind関数で内容を出力しています。
イベントを登録/修正するページ
イベントを登録するフォームを作成します。
まずは、「src/main/webapp」フォルダにsave.htmlというファイル名で、ダウンロードサンプルに含まれる同名のファイルと同じ内容のものを用意します。このテンプレートファイルは、EventSnippetのsave関数でフォームが出力されるようになっています。
フォームを出力するsave関数を、先ほど作成したEventSnippet.scalaに追加しましょう。追加する内容は、リスト8の通りです。
// イベント登録フォームの表示と、Submit時の保存を行います。
def save( xhtml:NodeSeq ) = {
// urlからidを取得し、idが指定されていたら
// データストアから検索する
val event = S.param("id") match {
case Full(id) => Event.find( id.toLong )
case Empty => None
case Failure(msg, _, _ ) =>
S.error( msg )
None
} // *1
// フォームの入力内容を保持するための変数 *2 val id = event map{ _.id } getOrElse( None )
var name = event map{ _.name } getOrElse("")
var description = event map{ _.description } getOrElse("")
var fromDate = event map{ _.fromDate } getOrElse( new Date )
var toDate = event map{ _.toDate } getOrElse( new Date )
var place = event map{ _.place } getOrElse("")
val join = event map{ _.join } getOrElse( 0L )
var count = event map{ _.count } getOrElse( 10 ) toString
// Submit時に呼び出されて、入力内容を基にデータストアへ保存する関数
def doSave = { // *5
Event.save(
Event( id, name, description, fromDate,toDate,
place, join, count.toLong )
)
redirectTo("/index") // 保存後はTopページへリダイレクト
}
// bind関数を利用してフォームを出力
bind( "event" , xhtml, // *3
"name" -> SHtml.text( name, name = _ ),
"description" -> SHtml.textarea( description, description = _,
"cols" -> "40", "rows" -> "6" ),
"fromDate" -> SHtml.text( fromDate, fromDate = _ ),
"toDate" -> SHtml.text( toDate, toDate = _ ),
"place" -> SHtml.text( place, place = _ ),
"join" -> join,
"count" -> SHtml.text( count, count = _ ),
"save" -> SHtml.submit( "Save", doSave _, "class"->"button") // *4
)
}
このsave関数は、リクエストパラメータにidがある場合は、*1でidを基にEventオブジェクトのfind関数を呼び出してデータストアを検索します。idに対応するデータがある場合は、フォームの初期値として設定しておくことで、修正画面としても利用できるようになっています。
*2から始まるvar変数は、フォームの入力内容を保存しておくための変数です。bind関数でフォームの各コンポーネントに割り当てられた関数オブジェクトは、入力値をこのvar変数に代入するようになっているため、submitされた時にはvar変数にはフォームの入力値が設定されていることになります。
*3は、おなじみのbind関数でフォームを出力しています。*4でsubmitボタンを生成し、submit時の処理として*5のdoSave関数が登録されています。
doSave関数は、フォームの入力値が保存されているvar変数の値を基にEventクラスを作成して、Eventオブジェクトのsave関数に渡してデータストアへの保存を実行しています。保存後は、Topページへリダイレクトされるようになっています。
このような、bind関数でのフォームの出力と、submit時にdoSave関数が呼び出されて保存を実行するような実装の形は、Liftのフォーム処理の基本形といってもよいでしょう。


