LoginSignup
3
3

More than 5 years have passed since last update.

PageLess と Turbolinks (Rails4) の組み合わせで、動作ページと非動作ページを切りかえる

Last updated at Posted at 2014-02-24

Rails4 の TurbolinksPageLess を、Rails 3 の example に沿った形で組み合わせて使うと

  • page A: PageLess が有効になっているページ (画面最下部までスクロールすると表示要素が追加でオートロードされる)
  • page B: PageLess を使っていないページ

というケースで、

  1. page A から page B に遷移しても、page B で PageLess が有効になったままになり、画面最下部までスクロールするとバックグラウンドで page A の page=2, page=3 (... page=n) が取得されてしまう
  2. そのため page B から page A に遷移して画面最下部までスクロールすると、本来 page=2 から取得を再開して欲しいのに page=4 (page=n+1) から取得してしまう

というような問題が起きる。

jquery.pageless.js のソース を読んでみると、最初の方に $.pagelessReset() という関数が定義されているので、page B にこれを入れてあげると 1. の問題は解決できる。ただ、その後 page B に戻っても page A で PageLess の動作が復帰しないという副作用が発生する。

そこで、抜本的な解決策として

  1. TurboLinks でページ遷移する際 page:change というイベントが発生するので、そのハンドラで「毎回 $.pagelessReset() → PageLess を動作させるページなら再度 PageLess を開始」という処理を行う。
  2. PageLess を動作させるページに「戻る」ボタンでも遷移した時、どのページまで読み込んだかをそのページに記録しておき、1. で PageLess を再開させる際は、その記録を元に再開させる。

という方法をとる。

1 については app/assets/javascripts ディレクトリに .js ファイルを用意して下記のような処理を入れる。

application_global.js
$(document).on('page:change', function(e) {
  $.pagelessReset();

  // PageLess を動作させるページの path を列挙
  pageless_paths = { '/items': true, '/users': true };

  var path = document.location.pathname;
  if (pageless_paths[path]) {

    var total_pages  = Number($('#pageless-total-pages').text());
    var current_page = Number($('#pageless-current-page').text());
    var loader_image = $('#pageless-loader-image').attr('src');
    var writeCurrentPage = function () {
      $('#pageless-current-page').text(String($.pagelessCurrentPage()));
    };

    $('#results').pageless({ totalPages: total_pages,
                 currentPage: current_page,
                 url: path,
                 loaderMsg: "Loading more results",
                 loaderImage: loader_image,
                 complete: writeCurrentPage});
  }
});

関数 $.pagelessCurrentPage() は、現状の jquery.pageless.js には用意されていないので、下記のように自分で追加する。currentPage は jquery.pagelss.js 内部でインクリメント (++) されているのでこうやって値を取得するしかなさそう。

diff ../jquery.pageless/lib/jquery.pageless.js app/assets/javascripts/jquery.pageless.js
100a101,104
>   $.pagelessCurrentPage = function () {
>     return settingOrFunc('currentPage');
>   };
> 
183c187,189
<     $container.unbind(namespace);
---
>     if ($container) {
>       $container.unbind(namespace);
>     }

修正後の 187〜189 行目では、上記 1 の使い方だと $container が未定義でも $.pagelessReset() が実行されエラーになるので、定義されているときのみ unbind するよう変更している (呼び出し側で try 〜 catch してもよい)。

$.pagelessCurrentPage() の結果は上記 application_global.js で PageLess を利用するページの view に #pageless-current-page という ID の要素へ記録している。下記が view に追加する要素。

index.html.erb
<!-- pageless -->
<img id="pageless-loader-image" style="display: none" src="<%= image_path('load.gif') %>">
<div id="pageless-total-pages" style="display: none"><%= @items.total_pages %></div>
<div id="pageless-current-page" style="display: none">1</div>

また、ここでは totalPages に対応する数や image_path() の結果を rails で view にセットしている。

Rails 3 の example では pageless という Rails の helper メソッドを view に埋め込んでいるが、これに該当する処理は上記の application_global.js で実行されるので削除する。

これですっきりと PageLess を Turbolinks と組み合わせて使えるようになった。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3