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
Help us understand the problem. What is going on with this article?

intra-martのスクリプト開発でimuiPageDialogの検索ウィンドウを作成する

対象となる開発形態

  • intra-mart AccelPlatform
    • スクリプト開発

やりたいこと

コード入力欄の隣に検索アイコンを設置して、クリックで検索画面を呼び出す。
検索画面で結果をダブルクリックしたら、呼び出し元画面のコード入力欄と名前に選択結果を反映する。
これをwindow.open()ではなく、imuiPageDialogを使用して実現する。

imuiPageDialogの仕様

  1. ベースになっているプラグインはjQuery UI Dialog。
  2. window.open()と違い、呼び出し元ページの内部にAjax処理でHTMLが展開される。
  3. 一度展開されたHTMLはダイアログを閉じても残ったまま。
  4. 呼び出すページに記述されたスクリプトはHTML上には展開されず、メモリのような場所に展開される?(chromeのDevToolを使うと、VM####.jsとしてスクリプトが確認できる)

このため、以下に注意しないと正しく動作してくれません。

注意点

1. 呼び出すページはimui-theme-builder-moduleをnothemeに設定する

呼び出したページのHTMLが呼び出し元ページの内部に展開される仕様のため、呼び出し元画面のヘッダスクリプトとimuiPageDialogのヘッダスクリプトが競合してしまい、正常に動作しなくなります。
このため、imuiPageDialog作成時のパラメータでテーマをnothemeに指定します。

sample.html
$('<div></div>').appendTo(document.body)
                .imuiPageDialog({
   title: 'ページダイアログ',
   url: 'test/pageDialog',
   parameter: {
      'imui-theme-builder-module': 'notheme'
   },
   position: [650, 300],
   modal: true,
   height: 750,
   width: 465
});

2. 呼び出し元のエレメントとidやnameが重複しないようにする

1.と同様に呼び出したページのHTMLが呼び出し元ページの内部に展開される仕様のため、別HTMLだからといって同じidを使用するとidが重複してしまい、スクリプトが意図しない動作をします。
解決策は、ファイル名やアプリケーションIDなどを先頭につけて絶対に重複しないルールにするくらいしか思いつきません。
ファンクションコンテナ側で、Identifierオブジェクトから一意の値を取得してid値に利用する方法も考えましたが、セレクタ指定が煩雑になるためあまりお勧めできません。
何かいい方法があればいいんですが。

sample.html
const pageDialogId = '#sample001';
$('<div></div>').attr('id', pageDialogId)
                .appendTo(document.body)
                .imuiPageDialog({
   title: 'ページダイアログ',
   url: 'pageDialog',
   parameter: {
      'imui-theme-builder-module': 'notheme',
      pageDialogId: pageDialogId
   },
   position: [650, 300],
   modal: true,
   height: 750,
   width: 465
});
pageDialog.html
<imart type="hidden"
   identifier=$identifier
   pageDialogId=$pageDialogId
/>

<!-- 作成する要素にoriginal-id属性を追加する -->
<imart type="imuiTextbox" id="textbox1" original-id="textbox1" value="text1" />

<script type="text/javascript">
   $(function() {
      // ファンクションコンテナで取得した一意の値
      let $id = $('input[name="identifier"]').val();
      // ページダイアログID
      let $pid = $('input[name="pageDialogId"]').val();

      // ページダイアログ内部のoriginal-id属性を持つ全てのエレメントについてid値をidentifier+idに書き換える
      $('#' + $pid + ' [original-id]').each(function(index, element) {
         element.attr('id', $id + element.attr('id'));
      });

      // 以降ID指定する場合はidentifier+idで指定する
      console.log($('#' + $id + 'textbox1').val());
</script>
pageDialog.js
// Identifierオブジェクトを利用して一意の値を取得
let $identifier = Identifier.get();
// リクエストパラメータのページダイアログID
let $pageDialogId;

function init(request) {
   $pageDialogId = request.pageDialogId;
}

3. 呼び出したダイアログは.remove()で破棄する

一度展開されたHTMLはダイアログを閉じても残ったままになるため、呼び出し元のcloseイベント処理で破棄してやる必要があります。
破棄しなかった場合、2回目以降のダイアログ呼び出し時に正常に動作しない可能性があります。

sample.html
let pageDialogId = '#sample001';
$('<div></div>').attr('id', pageDialogId)
                .appendTo(document.body)
                .imuiPageDialog({
   title: 'ページダイアログ',
   url: 'pageDialog',
   parameter: {
      'imui-theme-builder-module': 'notheme',
      pageDialogId: pageDialogId
   },
   position: [650, 300],
   modal: true,
   height: 750,
   width: 465,
   close: function(event, ui) {
      // imuiPageDialogIdを作成したdivを削除
      $('#' + pageDialogId).remove();
   }
});

4. 呼び出したページでAjax処理を実行する場合、Ajax関連のfunctionは使用する要素の前に記述する

これはページ内に記述したスクリプトがHTML内部には展開されないことによるものと思われますが、例えば呼び出したページでimuiListTableなどを使っている場合、<imart type="imuiListTable">タグの属性で指定するonAjaxErrorなどのAjax関連のfunction(というか、エレメントの生成時に使用するfunction)がタグの後方にあると、functionが認識されずエラーになります。
パフォーマンスを考慮してスクリプトを最後に記述するとエラーになってしまうので、Ajax関連のfunctionだけは先に記述する必要があります。
同じタグ内部で指定するfunctionでも、onDblClickRowなどのAjaxに関連しないfunctionはエレメント生成時に使用しないため、後方で記述しても大丈夫です。

pageDialog.html
<script type="text/javascript">
   // Ajax関連処理はimuiListTableの前に記述
   function pageDialog_onAjaxBeforeSend() {
      imuiShowSuccessMessage('Ajax前処理を開始しました。');
   }
   function pageDialog_onAjaxComplete() {
      imuiShowSuccessMessage('Ajax処理が完了しました。');
   }
   function pageDialog_onAjaxError() {
      imuiShowErrorMessage('Ajax処理でエラーが発生しました。');
   }
</script>

<imart
   type="imuiListTable"
   id="pageDialog_listTable"
   process="jssp"
   target="pageDialog"
   onAjaxBeforeSend="pageDialog_onAjaxBeforeSend"
   onAjaxComplete="pageDialog_onAjaxComplete"
   onAjaxError="pageDialog_onAjaxError"
   onDblClickRow="pageDialog_onDblClickRow"
   multiSelect="false"
   width="440"
   height="450"
>
   <cols>
      <col name="code" caption="code" />
      <col name="name" caption="name" />
   </cols>
</imart>

<script type="text/javascript">
   $(function() {
      console.log('Ajax以外の処理は後方でも大丈夫');
   });

   // imuiListTableの列ダブルクリックイベント
   function pageDialog_onDblClickRow(id) {
      // ダブルクリックされた行のデータを取得
      let data = $('#pageDialog_listTable').jqGrid('getRowData', id);
      imuiShowSuccessMessage('code:' + data.code + ' name:' + data.name);
   }
</script>

サンプルコード

ダブルクリックした行のデータを呼び出し元で取得するために、呼び出されるページ側でグローバル変数に名前空間を作成することにしました。
呼び出されたページで作成したグローバル変数は、imuiPageDialogが破棄された後も参照可能です。
名前空間を作成することで、グローバル変数の汚染も防止することができます。

上記注意点も意識しつつ、作成したコードは以下のようになりました。
idの重複については、Identifierは使用せず名称の先頭にファイル名を付けるようにしています。

sample.html
<imart type="imuiTextbox" id="textbox1" placeholder="code" />
<a href="javascript:void(0);">
   <span id="searchIcon" class="im-ui-icon-common-16-search"></span>
</a>
<imart type="imuiTextbox" id="textbox2" placeholder="name" />

<script type="text/javascript">
   $(function() {
      $('#searchIcon').on('click', function() {
         let pageDialogId = 'samplePageDialog';
         $('<div></div>').attr('id', pageDialogId)
                         .appendTo(document.body)
                         .imuiPageDialog({
            title: 'ページダイアログ',
            url: 'pageDialog',
            parameter: {
               'imui-theme-builder-module': 'notheme',
               pageDialogId: pageDialogId
            },
            position: [650, 300],
            modal: true,
            height: 750,
            width: 465,
            close: function(event, ui) {
               // imuiPageDialogIdを作成したdivを削除
               $('#' + pageDialogId).remove();

               if (pageDialog.trigger) {
                  // ダイアログで操作記録が取られた場合のみ実行
                  $('#textbox1').val(pageDialog.data.pageDialog_code);
                  $('#textbox2').val(pageDialog.data.pageDialog_name);

                  // 操作記録をクリア
                  pageDialog.trigger = '';
               }
            }
         });
      });
   });
</script>
pageDialog.html
<imart type="hidden"
   pageDialog_pageDialogId=$pageDialogId
/>

<script type="text/javascript">
   // Ajax関連処理はimuiListTableの前に記述
   function pageDialog_onAjaxBeforeSend() {
      imuiShowSuccessMessage('Ajax前処理を開始しました。');
   }
   function pageDialog_onAjaxComplete() {
      imuiShowSuccessMessage('Ajax処理が完了しました。');
   }
   function pageDialog_onAjaxError() {
      imuiShowErrorMessage('Ajax処理でエラーが発生しました。');
   }
</script>

<imart
   type="imuiListTable"
   id="pageDialog_listTable"
   process="jssp"
   target="pageDialog"
   onAjaxBeforeSend="pageDialog_onAjaxBeforeSend"
   onAjaxComplete="pageDialog_onAjaxComplete"
   onAjaxError="pageDialog_onAjaxError"
   onDblClickRow="pageDialog_onDblClickRow"
   multiSelect="false"
   width="440"
   height="450"
>
   <cols>
      <col name="pageDialog_code" caption="code" />
      <col name="pageDialog_name" caption="name" />
   </cols>
</imart>

<script type="text/javascript">
   // 名前空間
   if (typeof pageDialog === 'undefined') {
      let pageDialog = {}; 
   }

   // 操作記録をクリア
   pageDialog.trigger = '';

   // imuiListTableの列ダブルクリックイベント
   function pageDialog_onDblClickRow(id) {
      // ダブルクリックされた行のデータを取得
      pageDialog.data = $('#pageDialog_listTable').jqGrid('getRowData', id);
      // 操作を記録
      pageDialog.trigger = 'dblClick';

      // 呼び出し元から受け取ったpageDialogIdを利用してimuiPageDialogをcloseする
      $('#' + $('input[name="pageDialog_pageDialogId"]').val()).imuiPageDialog('close');

   }
</script>
pageDialog.js
// リクエストパラメータのページダイアログID
let $pageDialogId;

function init(request) {
   $pageDialogId = request.pageDialogId;
}

function getList(request) {
   let sampleData = [
      {pageDialog_code: 'A0000001', pageDialog_name: '上田辰男'},
      {pageDialog_code: 'Q0000002', pageDialog_name: '青柳辰巳'}
   ];

   return {
      data: sampleData
   };
}
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