LoginSignup
2
2

More than 5 years have passed since last update.

【Rails】FormのDirtyCheckをする(with Turbolinks, CKEditor)

Last updated at Posted at 2017-11-29

フォームなどで保存されていない内容を含むときに,ページを離れようとしている場合に次のようなアラートを出す.
Turbolinksを有効にしていて,form_for でつくられた普通のフォームや,WYSIWYGエディタckeditorを使っているケースに対応してみる.
jQuery製の AreYouSuredirtyForms でもいいが,細かい調整したかったので自作した.

image.png

検証環境

  • Rails 5.1.4
  • Turbolinks 5
  • WYSIWYGとしてckeditorを使用している

普通フォームのDirtyCheck

beforeunload イベントで window.appName.formDirty だけチェックしていると,フォームがサブミットされたタイミングでもDirtyとみなしてしまうので, window.appName.formSubmit でサブミットかどうかをチェックしている.

app/assets/dirty-forms.js
$(window)
    // フォームの状態を初期化
    .on('turbolinks:load', function () {
        if (!window.appName) window.appName = {};
        window.appName.formDirty = false;
        window.appName.formSubmit = false;
        window.appName.dirtyMessage = '保存していない内容が失われますが、よろしいですか';

        $(':input').change(function () {
            if (!window.appName.formDirty) window.appName.formDirty = true;
        });
        $('form').submit(function () {
            window.appName.formSubmit = true;
        });
    })
    // Turbolinksでページが切り替わるタイミング
    .on("page:before-change turbolinks:before-visit", function () {
        if (window.appName.formDirty) {
            return confirm(window.appName.dirtyMessage);
        }
    })
    // リロードされたり,タブやウインドウが閉じられる前のタイミング
    .bind("beforeunload", function (event) {
        if (!window.appName.formSubmit && window.appName.formDirty) {
            event.returnValue = window.appName.dirtyMessage;
            return event.returnValue;
        }
    });

CKEditorのDirtyチェック

すべてのCKEDITORのDirtyをチェックするカスタムメソッド hasDirtyForm を実装する.
CKEDITOR.instancesは checkDirty メソッドを持つので,そのどれかがDirtyかチェックしているだけ.

app/assets/ckeditor/index.js
//= require ckeditor/init.js.erb
//= require ./config
//`app/assets/ckeditor/config.js` では `CKEDITOR.editorConfig` を設定したり 
// `dialogDefinition` イベントを設定しているが内容は割愛.

// .ckeditorが付いている要素をWYSIWYG化する
$(document).on('turbolinks:load', function () {
    $('.ckeditor').each(function () {
        CKEDITOR.replace($(this).attr('id'))
    });
});

// すべてのCKEDITORのDirtyをチェックするカスタムメソッドを実装
CKEDITOR.hasDirtyForm = function () {
    var editors = this.instances;
    return Object.keys(editors).some(function (key) {
        return editors[key].checkDirty();
    });
};

page:before-change turbolinks:before-visitbeforeunload イベント時に CKEDITOR.hasDirtyForm() のチェックをするようにする.

app/assets/dirty-forms.js
$(window)
    •••
    .on("page:before-change turbolinks:before-visit", function () {
        if (window.appName.formDirty || CKEDITOR.hasDirtyForm()) {
            return confirm(window.appName.dirtyMessage);
        }
    })
    .bind("beforeunload", function (event) {
        if (!window.appName.formSubmit && (window.appName.formDirty || CKEDITOR.hasDirtyForm()) {
            event.returnValue = window.appName.dirtyMessage;
            return event.returnValue;
        }
    });
2
2
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
2
2