AjaxでPaginateする
タイトル通り。ぐぐってもスマートな方法が見当たらなかったので、PaginatorHelperからModelまでソースを読む羽目になったが、わかってみれば至極簡単だった。
口で説明するよかサンプルのが早いと思われるので、掲示板でも作りましょうか。
- CakePHP1.2
- /js/prototype.jsを設置
- 適当なDBを用意
まずモデル。名前はテキトーにThreadに。命名規則にしたがってテーブル名はthreadsね。
<?php /** CREATE TABLE threads ( id SERIAL NOT NULL -- Postgres以外の人は適当に読み替えて , handle VARCHAR(100) DEFAULT '名無しさん' , email VARCHAR(100) , comment TEXT not null , created TIMESTAMP , PRIMARY KEY (id) ) */ class Thread extends AppModel { var $name = 'Thread'; // ほんとはちゃんとバリデータ書こうね var $order = 'created desc'; //最新の書き込みを先に } ?>
コントローラをつくる。controllers/threads_controller.php
<?php class ThreadsController extend AppController { // RequestHandlerを呼んでおくとAjaxかどうか自動的に判断してくれる var $component = array('RequestHandler'); // JavascriptHelperはprototype.jsをview側で読まないなら不要(layoutで読むとか) var $helpers = array('Html', 'Form', 'Ajax', 'Javascript'); // 2行で書ける掲示板\(^o^)/ function index(){ if(!empty($this->data)) $this->Thread->save($this->data); // $this->dataあったら投稿 $this->set('threads',$this->paginate()); // 再表示 } } ?>
次にビュー作る。views/threads/index.ctp
<?php $javascript->link('prototype',false); // prototype.jsを読み込みlayoutで読むなら不要 // 投稿後に最新の場所に移動させるためのURL。 // order by created descでひっくり返してるのでpage:1。最後ならpage:lastとすればOK。 $url = '/threads/index/page:1'; // Ajax.UpdaterをかけるDOM_ID // optionsにarray('update'=>DOM_ID)って書くのダルいからcompact('update')ってかけるように$update $update = 'ThreadsIndex'; ?> <?php if( !$ajax->isAjax() ): ?> <h2>掲示板だゴルァ</h2> <!-- Ajaxリクエストじゃなかったらタイトル表示 --> <?php endif; ?> <?php echo $ajax->div($update) ?> <!-- AJAXリクエストの時は表示されない --> <?php echo $paginator->prev("<<",compact('update'))?> <?php echo $paginator->numbers(compact('update'))?> <?php echo $paginator->next(">>",compact('update'))?> <?php if(empty($threads)):?> <p>書き込みはまだありませんが何か(゚Д゚)?</p> <?php endif;?> <?php foreach( $threads as $thread ):?> <!-- カキコ表示ループ部分 エスケープわすれてはならぬぞ --> <div> <p> <?php echo $html->tag('span',$thread['Thread']['handle'],array('title'=>$thread['Thread']['email']),true)?> <?php echo $html->tag('span',$thread['Thread']['created'],array(),true)?> </p> <p> <?php echo $html->tag('span',$thread['Thread']['comment'],array(),true)?> </p> </div> <?php endforeach; ?> <!-- このへんからフォーム --> <?php echo $ajax->form(null,'post',compact('update','url'))?> <!-- ほんとうは普通にform->input並べようね --> <?php echo $ajax->Form->inputs(array('Thread.handle','Thread.email','Thread.comment'))?> <?php echo $ajax->Form->end('投稿')?> <?php echo $ajax->divEnd($update) ?> // AJAXリクエストの時は表示されない
CakePHPの流儀を知らないとかなり意味不明な感じになりますが(アクションとかマジで)
とりあえずこんな記事読む人ならCakePHPはそれなりに使ってるだろうということで要点だけ
- $ajax->div(),divEnd()はAjaxでリクエストされた場合、何も出力しない
- ビューでAjaxかどうかの分岐には$ajax->isAjax()を使う
- あんまりにも2つのビュー(AJAXとそれ以外)が違う場合はコントローラで$this->RequestHandler->isAjax()で分岐して$this->render()とかやるべき?
- $ajax->form(),$paginator->prev(),next(),numbers()などは$options['update']='DOMエレメントのID'を投げてあげると全部AjaxリクエストとしてよしなにEvent.observe吐いてくれます。
- Configure::write('debug',0)にしないとデバッグライトがずどーんて出るので適当に(beforeFilterとか)挿入してネ。
次は同一ページで複数モデルのPaginateネタとかやろう。