Help us understand the problem. What is going on with this article?

YiiのPaginationをブラウザの戻るボタンに対応させる

More than 5 years have passed since last update.

CListViewCGridView のPaginationは、デフォルトでAjaxを使うようになっていて、次のページがリンクしているリソースを再ロードしないので、レスポンスも高速だしサーバにも優しいです。
しかも、非常に高度なHTMLとJavaScriptでPaginationまで付けてくれるのに、ビューに書くコードはせいぜいこれぐらいでOKという優れもの。

<?php $this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$dataProvider,
    'itemView'=>'_view',
)); ?>

ところが、これらのウィジェットは、デフォルトではひとつ困ったことがあります。それはブラウザのヒストリに前のページが残らないこと。何かの項目をクリックして詳細を閲覧し、「あ、これじゃない」と思ってとっさに戻るボタンをクリックしたとき、その項目があった状態に戻れないんですね。前の状態がAjaxで変化した結果なので。というわけで、それに対応する方法を少し。

対策1 Ajaxをやめる

<?php $this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$dataProvider,
    'itemView'=>'_view',
    'ajaxUpdate'=>false,  // これ追加
)); ?>

はい、これだけでAjaxをオフにでき、2ページ目以降に行くと、HTML全体がリロードされるようになります。で、URLには、Item_page=2 とかそんな感じのパラメータが付くことになります。

ただしこの方法だと、ページを送るたびに1ページ分まるごとリクエストやり直しになり、せっかくリンクしている jQuery が使われなくてもったいないですね。まあ、これでも普通のページ送りですが、ちょっとWeb2.0フレームワーク感がない。

対策2 pjaxにする

で、次の方法は Yii 1.1.11 からなので最近のプロジェクトでないとダメかもしれませんが、マジですごくいいです。なんとこのバージョンで、CListViewCGridViewenableHistory というステキなプロパティが増えました。

<?php $this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$dataProvider,
    'itemView'=>'_view',
    'enableHistory'=>true,  // これを追加
)); ?>

こうすると、AjaxでDOMを更新しつつ、ブラウザのアドレスバーに履歴を残してくれます。いわゆる pjax というやつです。GitHubのソースを閲覧するときフォルダを掘ったり戻ったりするアレですね。

やってみると、対策1と見た目が同じに見えるかもしれませんが、ブラウザのデバッガでよく調べると、HTML全体がリロードされていないことがわかります。

また、微妙な変化ですが、ページのスクロール位置が維持されていると思います(環境によるので保証はないですが)。この次へボタンが同じ位置を維持するというのは、わりとUIの使いやすさにつながるんですよね。

http://www.yiiframework.com/doc/api/1.1/CListView#enableHistory-detail

http://www.yiiframework.com/doc/api/1.1/CGridView#enableHistory-detail

ただしこれ、ブラウザが pushState をサポートしている必要があります。また、アドレスバーは1つしかないので、1ページ内に複数の CListViewCGridView を置いて両方 pjax したいというのはダメです。

Yii のソースには History.js が含まれてたので、少々古いIEでもなんとか動くようにしてくれるかもしれませんが、そこはちょっと未検証。

(実はこれ書いてる本人が、softark さんに教えてもらうまでこの新プロパティが増えてたことを知りませんでした。YiiのCGridViewでpushStateできたらいいのにって、もう1.1.12がリリースされてるのに言ってた/// どうもありがとうございます。)

pjaxがダメだったときすぐAjax更新をオフにできるように

オススメはpjaxですが、もしユーザの多くがpjaxできない場合、彼らにはデフォルトのAjax更新を強いることになります。そうなったときユーザが「サーバ負荷は気にしないからブラウザの戻るボタンを効かせたい」と言い出したら、すぐにAjax更新を使わないほうの対策に切り替えたいですね。

Yii:app()->widgetFactory コンポーネントを config/main.php で構成して、特定の種類のウィジェットが作られるときのシステム全体でのデフォルト値を指定しておけば、変更スポットを集約しておけます。

protected/config/main.php
<?php

    'components'=>array(
        ...
        'widgetFactory'=>array(
            'widgets'=>array(
                'CListView'=>array( // CListViewのデフォルト
                    'enableHistory'=>true, // pjax on
                    'ajaxUpdate'=>true, // ajax on
                ),
                'CGridView'=>array( // CGridViewのデフォルト
                    'enableHistory'=>true, // pjax on
                    'ajaxUpdate'=>true, // ajax on
                ),
                ...
            ),
        ),

これで、config/main.php に登録したウィジェットを使っている箇所では、カスタマイズされた設定を使いつつ、ソース上ではGiiが生成したまんまに近いコードを維持できます。

<?php $this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$dataProvider,
    'itemView'=>'_view',
)); ?>

デフォルトは main.php から引き継ぎ、アドホックに必要なものはその場で指定したものに。

これで、今後Giiで新しいビューを作ったときも、コード変更なしで同じ方針が引き継げて便利ですね。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away