対象となる開発形態
- intra-mart AccelPlatform
- スクリプト開発
やりたいこと
コード入力欄の隣に検索アイコンを設置して、クリックで検索画面を呼び出す。
検索画面で結果をダブルクリックしたら、呼び出し元画面のコード入力欄と名前に選択結果を反映する。
これをwindow.open()
ではなく、imuiPageDialog
を使用して実現する。
imuiPageDialogの仕様
- ベースになっているプラグインはjQuery UI Dialog。
-
window.open()
と違い、呼び出し元ページの内部にAjax処理でHTMLが展開される。 - 一度展開されたHTMLはダイアログを閉じても残ったまま。
- 呼び出すページに記述されたスクリプトはHTML上には展開されず、メモリのような場所に展開される?(chromeのDevToolを使うと、VM####.jsとしてスクリプトが確認できる)
このため、以下に注意しないと正しく動作してくれません。
注意点
1. 呼び出すページはimui-theme-builder-moduleをnothemeに設定する
呼び出したページのHTMLが呼び出し元ページの内部に展開される仕様のため、呼び出し元画面のヘッダスクリプトとimuiPageDialog
のヘッダスクリプトが競合してしまい、正常に動作しなくなります。
このため、imuiPageDialog
作成時のパラメータでテーマをnotheme
に指定します。
$('<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値に利用する方法も考えましたが、セレクタ指定が煩雑になるためあまりお勧めできません。
何かいい方法があればいいんですが。
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
});
<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>
// Identifierオブジェクトを利用して一意の値を取得
let $identifier = Identifier.get();
// リクエストパラメータのページダイアログID
let $pageDialogId;
function init(request) {
$pageDialogId = request.pageDialogId;
}
3. 呼び出したダイアログは.remove()で破棄する
一度展開されたHTMLはダイアログを閉じても残ったままになるため、呼び出し元のclose
イベント処理で破棄してやる必要があります。
破棄しなかった場合、2回目以降のダイアログ呼び出し時に正常に動作しない可能性があります。
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はエレメント生成時に使用しないため、後方で記述しても大丈夫です。
<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
は使用せず名称の先頭にファイル名を付けるようにしています。
<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>
<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>
// リクエストパラメータのページダイアログ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
};
}