jQuery Deferredで作るオリジナル確認ダイアログ

ある意味、前回(オリジナルのダイアログを閉じた時に、元の要素にフォーカスを戻す方法 | while(isプログラマ))のつづき。今回は確認ダイアログ版。

ただ、今回のエントリーはダイアログを作ることではなく、jQuery Deferredの勉強のメモです。最近になってjQuery Deferredについて調べてみました。まだまだ分かっていないことは多いのですが、試しにjQuery Deferredを使った確認ダイアログを作成することにしました。

今回作るのは、標準のconfirmメソッドを使うと下記のようなものです。

// ボタンクリック時の処理
$('#open-confirm-btn').click(function(e){
    if(window.confirm('Googleではなく、Yahooに行きますか?')){
        location.href = 'http://www.yahoo.co.jp/';
    }else{
        location.href = 'http://www.google.co.jp/';
    }
});

つまり、確認ダイアログを表示して、『OK』を押せばYahoo!JAPANへ、『キャンセル』を押せばGoogleへ飛ぶという処理です(キャンセルなら何もしないのが普通じゃないかと思われそうですが、分かりやすいようにどちらも何かしらの動作をするようにします)。

ただ、これだとダイアログのレイアウトを変更できないので、独自のダイアログを作成することに。ついでに、上記のYahoo!やGoogleに飛ぶ処理をjQuery Deferredで実現することにしました。試しに書いてみたコードが下記です。

var $dialog = $('#TestDialog');
// ダイアログを開く関数
var openConfirm = function(msg){
    $dialog.find('.dialog__box__message').html(msg);
    $dialog.removeClass('dialog--hide');
    // 現在のフォーカスを取得
    var current_focus = document.activeElement;
    $dialog.data('back-focus', current_focus);
    $dialog.find('.ok-btn').focus();

    // jQuery Deferredの処理
    var d = $.Deferred();
    $dialog.data('deferred', d);
    return d.promise(); // 『return d』でも動いた。promiseオブジェクトを返すのが一般的らしい。promiseオブジェクトでは、resolveやrejectができない(https://app.codegrid.net/entry/deferred-1#Headings-deferred-1-6)
}
// ダイアログ内のボタンクリック時の処理
var onClickDialogBtn = function(){
    $dialog.addClass('dialog--hide');
    // フォーカスを戻す処理
    var next_focus = $dialog.data('back-focus');
    $(next_focus).focus();

    return $dialog.data('deferred');
}
// ダイアログのOKボタンを押した時の処理
$dialog.find('.ok-btn').click(function(e){
    var d = onClickDialogBtn();
    if(d && d.resolve){
        d.resolve(); // 正常終了を通知
    }
});
// ダイアログのキャンセルボタンをおした時の処理
$dialog.find('.cancel-btn').click(function(e){
    var d = onClickDialogBtn();
    if(d && d.reject){
        d.reject(); // 異常終了を通知
    }
});

// ボタンクリック時の処理
$('#open-confirm-btn').click(function(e){
    openConfirm('Googleではなく、Yahooに行きますか?')
        .done(function(){ location.href = 'http://www.yahoo.co.jp/' })
        .fail(function(){ location.href = 'http://www.google.co.jp/' })
});

サンプル:ダイアログのテスト

ようは、OKボタンを押した時にresolveメソッドを呼び、doneメソッドの引数に入れた関数を呼ぶ。キャンセルボタンを押した時にrejectメソッドを呼び、failメソッドの引数に入れた関数を呼ぶという処理をしています。

このぐらいならjQuery Deferredを使う必要はないんですけどね。そもそもキャンセルボタンを押すことが何でreject(異常終了)なのかと突っ込まれそうです。多分、この例はjQuery Deferredを使う例としては間違っていると思います。

ところで、jQuery Deferredを調べていると、Deferredオブジェクトの取得に『new $.Deferred』としているページが多々ありました。なので、Deferredオブジェクトかどうかの判定には『obj instanceof $.Deferred』とすればいいだろうと思ったのですが、結果はfalseになってしまいました。なぜだろう? と思って、jQueryのコードを見てみると、Deferredメソッド内で作成したオブジェクトをreturnしており、Deferred自身のインスタンスを生成しているわけではないようです。jQueryの公式ページのサンプルコードでは、Deferredオブジェクトの取得にnewをつけていません(deferred.promise() | jQuery API Documentation)。やたら、newを付けている解説ページが多いのだけど、なぜそうなったのだろうか・・・。

ところで、今回作成したopenConfirmメソッドでは、promiseメソッドで取得したpromiseオブジェクトを返していますが、ここはDeferredオブジェクトをそのまま返しても結果は変わりません。promiseオブジェクトとの違いとしては、promiseオブジェクトにはresolveやrejectがありません。それだけの違いですが、一般的にpromiseオブジェクトを返すようにするそうです。この辺りは、書きページの『deferred図解』の『なぜわざわざpromiseを渡すのか』を参考にしてください。
参考:jQuery deferredの使い方 – deferredの基本 | CodeGrid

jQuery Deferredはいろいろ応用ができそうな機能です。複数のDeferredオブジェクトを使ってwhenメソッドを使うとか。ただ、自分自身よく分かってないところもあるので、もう少し勉強しようと思います。

コメント

タイトルとURLをコピーしました