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

window.openでモーダルぽくする

More than 5 years have passed since last update.

Chromeではwindow.showModalDialogは使用できません。

「WEBサイトでポップアップが開かれて、開かれた画面(子画面)で何か選択すると、
元の画面(親画面)に選択された内容が反映される。」
ていうやつWEBサイトを開発してたらよくありますよね?

そんな時のやりたいこと、、、、、、
- 子画面が開いている時は親画面をいじられたくない。
- 親画面のElementを操作したい。
- 子画面を閉じると、親画面にフォーカスを当てたい。

window.showModalDialogを使って子画面を開き、
子画面で親画面のElementを取得し、
子画面を閉じると親画面にフォーカスが当たってくれます。

親画面の処理

// windowをモードダルで開く
// 第一引数Url、第二引数子画面をに渡す値
window.showModalDialog('sub.html',this,'width=400, height=300');

子画面でボタンを押した時などの処理

// 親画面から渡ってきた値を取得
// 今回は親画面のElementを操作する為windowを渡した
var parentWindowObject = window.dialogArguments;

// 親画面のelement1を取得
var element1 = parentWindowObject.document.getElementById('hoge1');
// element1に値を設定
element1.value = '値1';
// 親画面のelement2を取得
var element2 = parentWindowObject.document.getElementById('hoge2');
// element1に値を設定
element2.value = '値2';
// 子画面の終了
window.close();

簡単ですね・・・・

でも
ChromeではshowModalDialogが使えません。
クリックイベントなどでshowModalDialogを記載して、ボタンを押しても
Chromeだとウンともスンとも言ってくれませんでしたorz

なので、僕は以下の方法で、やりたいことを実現しました。

showModalDialogが使えない時

親画面の処理

// 適当に高さを指定してwindow.openでポップアップ画面を開く
var openWindow = window.open('sub.html','sub','width=400, height=300');
// 親画面にシェードをかける処理を実施
 ~ 処理の内容は省略 ~

// 1秒間隔で子画面の状態を監視
var interval = setInterval(function()
{
    // 子画面が閉じていたら
    if(!openWindow || openWindow.closed)
    {
        // 親画面のシェードを外す処理
        ~ 処理の内容は省略 ~

        // Intervalを破棄
        clearInterval(interval);
    // 画面が起動していたら
    }
    else
    {
        // 子画面にフォーカスを当てる
        if(!openWindow.document.hasFocus())
        {
            openWindow.focus();
        }
    }
},1000);

子画面の処理① ~ボタン押下等の処理~

// 親画面の存在確認
// 存在しなかったら次画面(子画面)を閉じる
if(!window.opener || window.opener.closed)
{
    window.close();
}
else
{
    // 親画面を取得
    var parentWindowObject = window.opener;
    // 親画面のelement1を取得
    var element1 = parentWindowObject.document.getElementById('hoge1');
    // element1に値を設定
    element1.value = '値1';
    // 親画面のelement2を取得
    var element2 = parentWindowObject.document.getElementById('hoge2');
    // element1に値を設定
    element2.value = '値2';
    // 子画面の終了
    window.close();
}

子画面の処理② ~子画面自身の状態確認~

    $(document).ready(function()
    {
        $(window).on("beforeunload",function(e)
        {
             window.opener.focus();
        });
    });

です。

まとめ

window.showModalDialogで渡した親画面のObjectについては
window.openの場合はwindow.openerで取得することができます。

window.openの戻り値は子画面のObjectになります。

またjQueryの処理になりますが、
子画面起動後、setIntervalを行うことにより、
Timer処理で子画面の状態を監視できます。
while等を使ってループさせてしまうと、画面が固まるので
setIntervalでTimer処理を行います。

子画面が閉じられたと判断したら
clearIntervalでTimer処理を破棄します。

子画面が開いているときは、
openWindow.document.hasFocus
で子画面にフォーカスが当たっているか判断して、
当たっていなかったらopenWindow.focusでフォーカスを当てます。

openWindow.document.hasFocusの判定を行わずに
フォーカスを当て続けると、テキストボックス等に値を入力しているときに
Window全体にフォーカスが当たってしまうので、入力が途中でキャンセルされちゃいます

最後に子画面の監視処理です。
今回はjQueryを使ってwindowのbeforeunloadイベントをバインドしました。
これにより×ボタンでWindowを閉じてもイベントをひろうことができます。

完全なモーダルの場合は子画面を閉じると親画面にフォーカスがあたるのですが、
window.openで起動するとモードレスになるので、
親画面を最小化したりして親画面のIEを見失った時には便利です。

以上

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