[Lift-Wiki]Example: Paginating Mapper-based snippets with sortable headers
ソートヘッダー付のPaginateをサクッと作れるのですが、上記サンプルが中途半端なので補完してみます。
バージョンはLift1.1-M7です。まだAPI変わる可能性あるので、その辺りは注意してください。
■View
<lift:surround with="default" at="content">
<lift:userView.list>
<nav:records/> <br/>
<nav:first/> <nav:prev/> <nav:allpages> | </nav:allpages> <nav:next/> <nav:last/>
<table>
<tr>
<th><sort:id><lift:loc>ID</lift:loc></sort:id></th>
<th><sort:email><lift:loc>mail</lift:loc></sort:email></th>
<th><sort:nickname><lift:loc>ニックネーム</lift:loc></sort:nickname></th>
</tr>
<f:users>
<tr>
<td><f:id /></td>
<td><f:email /></td>
<td><f:nickname /></td>
</tr>
</f:users>
</table>
</lift:userView.list>
</lift:surround>
名前空間のnav/sortは決まっている値。
ポイントは、繰り返し表示する箇所(user行)を<f:items /> <f:users />で括っているところ。
■Snippet
import net.liftweb.mapper.view._
class UserView extends ModelSnippet[User] {
//必須でoverride
override val view = new ModelView( User, this )
override def edit(xhtml: NodeSeq):NodeSeq = <h1>Edit</h1>
val paginator =
new Paginator(User, this, User.id,//初期ソートカラム
"id" -> User.id, "email" -> User.email, "nickname" -> User.nickname )
def list(xhtml: NodeSeq):NodeSeq = {
//行繰り返し用のテンプレート<f:users></f:users>を切り出しておく
val innerTemplate = ( xhtml \\ "users" first ).descendant(1)
bind("f",
paginator.paginate(xhtml), //xhtmlを->pagenate用テンプレートに変換
"users" -> bindUsers(innerTemplate) //f:usersをrender
)
}
private def bindUsers(xhtml: NodeSeq):NodeSeq = {
paginator.page.flatMap( user => {
bind("f", xhtml,
"id" -> Text( user.id.toString ),
"email" -> Text( user.email ),
"nickname" -> Text( user.nickname ) )
})
}
}
snippet内で、繰り返す/繰り返さない箇所が混在するときは、ViewにしるしをつけてSnippet内で分解してやる。・・というのは自分はよく使ってる方法ですが、他にうまい方法ご存知の方はぜひ教えてください。
Paginatorにクエリを指定するには、
Paginator#constantParams
ページの表示件数を指定するには、
Paginator#num
に値を入れます。mapper.view.Paginatorのソースはとてもシンプルなので、継承して"流れるような"インターフェースにしたりも十分できそう。
さすがにRailsのpaginateほど美しくはないですが、満足です。