Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@jkr_2255

Turbolinks 5とJavaScriptウィジェットを共存させる

More than 3 years have passed since last update.

Turbolinks 5にすると、JavaScriptまわりで正しく動かすためにいろいろ工夫が必要となりました。今回は、MagicSuggestというウィジェットを例に、対応するためにしたことをまとめていきます。

なお、自分が以前書いた、Turbolinks 5に関する記事もご覧いただくと、よりわかりやすいかもしれません。

Turbolinks 5の場合に、注意すべき点

「ページ表示のタイミングでのイベントが違う」という点は以前にも触れましたが、それ以外にも、「ブラウザバックした場合」の挙動がふつうの場合と大きく違っています。以下に、ブラウザバックする場合の概ねの流れを示してみます。

  1. ページを表示する(turbolinks:loadなどのイベントが流れる)
  2. ページ遷移しようとする(Turbolinksでの処理が起きる)
  3. 現在のページでturbolinks:before-cacheイベントが走る
  4. 現在のページのDOMを保存する
  5. 移動した先のDOMを描画する
  6. (移動先のページ)
  7. ブラウザバックを押すと、Turbolinksに制御が移る
  8. 保存したDOMをロードして、turbolinks:loadイベントを実行する
  9. ロードしたDOMを描画して、戻る処理が完了

ここで注意点としては、DOMの保存は.cloneNode(true)で行われるので、ネイティブ・jQueryを問わず、イベントはすべて削除されます。とはいえ、一般的な場合、

  • DOMノード…保存して復活するので、問題なく動く
  • JavaScriptイベント…turbolinks:loadでセットすれば、新規表示時にも発動し、ブラウザバック時にも全削除→再セットとなって、問題なし

となるので、正常に動く…ように思えます。

JavaScriptからウィジェットを追加する場合

ここで問題になるのが、JavaScriptからDOMまで変えてしまうようなウィジェットを追加するような場合です。そのままにしていると、

  • 新規ロード時…DOMを書き換えてウィジェットを生成、それにイベントをセット
  • ブラウザバック時…「書き換え後のDOM+イベントなし」の状態からウィジェット生成コードが走って、うまく動かない場合がある

作戦としては2つあって、自分でDOM変更やイベントのセットを書いている場合には、「すでにDOMが変更されていればバイパスする」という方法があります。ただ、プラグインで行う場合はそうも行きません。

MagicSuggestとは

今回テーマとして取り上げたMagicSuggestは、複数選択可能なselectをドロップダウン形式にしてしまう、というもので、設定次第ではQiitaのタグ欄のような「フリー入力+既存リストから選択」ということもできます。

そこそこ長さのあるリストから複数選択させたいときに便利だったのでよく使っていたのですが、Turbolinks 5になったことで対応が必要となりました。

動くようにはなりました

「MagicSuggestのイベントだけセット」という器用な芸当はできないので、「もともとあった<select>要素をバックアップしておいて、キャッシュ記録時に書き戻す」という方法で対応を行うことにしました。なお、jQuery側に手当をして、ページ遷移ごとにreadyが発動するようにしてあります。

app/assets/javascript/magic_suggest.js
//= require magicsuggest

jQuery(function() {
  'use strict';
  // ページバック時の書き戻し用に、本来のドロップダウンをバックアップ
  var params = {
    /* 略 */
  };
  $('.magic-suggest').each(function(){
    var $elem = $(this);
    var cloned = this.cloneNode(true);
    $elem.magicSuggest(params);
    $('#' + this.id).data('original_select', cloned);
  });
  $(document).one('turbolinks:before-cache', function(){
    $('.ms-ctn').each(function(){
      var $this = $(this);
      $this.replaceWith($this.data('original_select'));
    });
  });
});

バックアップからの書き戻しは一度でいいので、.oneで単発イベントとしてあります。

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  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
jkr_2255
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?