window.showModalDialogをwindow.openへ移行したときにやったこと

window.showModalDialogをwindow.openへ移行したときにやったことです。

window.showModalDialogをwindow.openへ移行したときにやったこと

いずれも新しいウィンドウを開くという仕組みは同じですが、Google ChromeではshowModalDialogが動作しません。

かつて標準ブラウザがIEってシステムはたくさんありました。IEのサポートが2022年6月16日(日本時間)をもって終了することから、慌ててChromeへ移行している企業もあるようですね。今回の記事を書くきっかけになったのも、筆者がそんな案件を請け負ったからです。

今回は window.showModalDialogをwindow.openへ移行したときにやったこと を紹介します。


子画面から親画面への値の返し方

showModalDialogを使った場合、その多くがwindow.returnValueを使って親画面へ値を返していたのではないでしょうか?

window.opener.document.main.elementId.valueを使っても返せるけど、汎用性がなくなってしまうためあんまり使われてなかったんじゃないかな。親画面と子画面を疎結合にするために、window.returnValueにあらかじめ必要となる値を詰めて返すって方法が取られていたと推測します。

おそらくこんな感じのコードじゃないですかね。

親画面(parent.html)


<main class="m-3">
  <div class="form-group">
    <label for="code">コード</label>
    <input type="text" class="form-control" id="code">
  </div>
  <div class="form-group">
    <label for="code">なまえ</label>
    <input type="text" class="form-control" id="name">
  </div>
  <input type="button" class="btn btn-primary" value="子画面を開く"
    onclick="
      var returnValue = window.showModalDialog('child.html');
      if(returnValue) {//子画面が×で閉じられてなければ子画面の値をセットする
        document.getElementById('code').value = returnValue.addr_code;
        document.getElementById('name').value = returnValue.addr_name;
      }
  "/>
</main>

子画面(child.html)


<main class="m-3">
  <div class="form-group">
    <label for="code">コード</label>
    <input type="text" class="form-control" id="addr_code" value="tokyo">
  </div>
  <div class="form-group">
    <label for="code">なまえ</label>
    <input type="text" class="form-control" id="addr_name" value="東京">
  </div>
  <input type="button" class="btn btn-primary" value="親画面に反映"
    onclick="
      window.returnValue = {//値を詰めて返す
        addr_code: document.getElementById('addr_code').value,
        addr_name: document.getElementById('addr_name').value
      };
      window.close();
  "/>
</main>

showModalDialogのサンプル

showModalDialogのいいところは、モーダルにして他の処理をブロックできること、子画面で値を選んで親画面で必要な処理ができること、他の画面からも子画面が呼び出せること、などがあげられますね。

window.openにcallbackを実装して代用する

window.showModalDialogが使えないとなれば、window.openで代用するしかありません。親画面でCallbackのIDを発番し、子画面が閉じるときに指定したCallbackを呼び出すことで対応できます。

コードを書くとこんな感じです。

親画面(parent.html)


<main class="m-3">
  <div class="form-group">
    <label for="code">コード</label>
    <input type="text" class="form-control" id="code">
  </div>
  <div class="form-group">
    <label for="code">なまえ</label>
    <input type="text" class="form-control" id="name">
  </div>
  <input type="button" class="btn btn-primary" value="子画面を開く"
    onclick="
      //var returnValue = window.showModalDialog('child.html');
      //if(returnValue) {//子画面が×で閉じられてなければ子画面の値をセットする
      //  document.getElementById('code').value = returnValue.addr_code;
      //  document.getElementById('name').value = returnValue.addr_name;
      //}
      var callbackId = 'callback_1234'; //子画面に合わせて適当にIDをふる
      window[callbackId] = function(returnValue) { //windowにコールバックを登録
          document.getElementById('code').value = returnValue.addr_code;
          document.getElementById('name').value = returnValue.addr_name;
      }
      //第2引数でCallbackのID名を渡す。子画面側では window.name として取得できる。
      window.open('child.html', callbackId, 'width=300,height=250,menubar=no,location=no,resizable=no,scrollbars=no,status=no');
  ">
</main>

子画面(child.html)


<main class="m-3">
  <div class="form-group">
    <label for="code">コード</label>
    <input type="text" class="form-control" id="addr_code" value="tokyo">
  </div>
  <div class="form-group">
    <label for="code">なまえ</label>
    <input type="text" class="form-control" id="addr_name" value="東京">
  </div>
  <input type="button" class="btn btn-primary" value="親画面に反映"
    onclick="
      //window.returnValue = {//値を詰めて返す
      //  addr_code: document.getElementById('addr_code').value,
      //  addr_name: document.getElementById('addr_name').value
      //};
      var callbackId = window.name; //window.nameに第2引数で指定した値が入っている
      var returnValue = {
        addr_code: document.getElementById('addr_code').value,
        addr_name: document.getElementById('addr_name').value
      };
      window.opener[callbackId](returnValue); //指定されていたコールバックを呼び出す
      window.close();
  ">
  1. 親画面でコールバック関数をwindowオブジェクトへ登録する。
  2. window.openの第2引数にコールバック関数名を設定する。
  3. 子画面でwindow.nameからコールバック関数名を取得する。
  4. 子画面で親画面のコールバックを呼んで値を返す。

サンプルはこちら

まとめ

window.showModalDialogをwindow.openへ移行したときにやったことを紹介しました。

今回紹介した記事の中ではshowModalDialogの特徴であった「他の処理をブロックできる」というモーダル特有の機能はないです。試してないですがフォーカスを子画面に充てるなどで対応できるのかも。

ちなみに本コードのHTMLをそのままブラウザで実行すると「Blocked a frame with origin "null" from accessing a cross-origin frame.」というエラーがでます。XAMPPのApacheなどを利用して「http://」で実行してくださいね。

IE(Internet Explorer)は、2022年6月16日(日本時間)をもってサポートが終了します。他のブラウザへの移行やコンテンツの改修など、とにかく速やかに実施することをおすすめします。

おつかれさまでした。

この記事がお役に立ちましたら シェア をお願いいたします。