フォームデータ送信後、DB更新に成功したら印刷プレビューを開く
画面から、任意の項目を選択→確認画面へ移行→OKボタン押下でサーバへ送信した後
DB更新に成功したら、元のページで印刷プレビューを開いてほしいな、と言われました。
ちなみに、struts2のプロジェクトです。
当初、ajax使って〜とのことだったので、jQuery.ajax()でasync:falseを指定して
実装してみたのだけど、jQuery1.8以降非推奨らしいし、エラーも出てしまう。
(Choromeで確認)
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.
これはちょっと嫌な感じなので、今回はformを使うことを考えてみました。
1.フォーム送信〜DB更新するところまで
まず、jsp側(抜粋)。
<div class="print-off"> <s:form> <input id="printStatus" type="hidden" value='<s:property value="printStatus" />'/> <s:iterator status="st" value="idList"> <input type="hidden" name='idList[<s:property value="#st.index" />]' value='<s:property value="idList[#st.index]" />' /> </s:iterator> <s:submit method="updateStatus" value="一括印刷"/> </s:form> </div> <div class="print-on"> ・・・ </div>
「print-on」クラスを持つ要素は、通常はCSSで非表示にしておいて
印刷プレビューを表示するときだけ表示。
「print-off」クラスを持つ要素は、その逆です。
(印刷のときに、ボタンとか余計なものを入れないための処置)
また、hiddenの<input>タグは、以下の用途に使います。
・printStatus・・・DB更新結果を保持する
・idList[<s:property value="#st.index" />]・・・印刷したいIDの配列要素
Action側(抜粋)。jsp側の<s:submit>タグで指定した「updateStatus」メソッドを作り
その中でDB更新するだけです。抜粋っていうか、日本語しか書いていない。。。
public class TestAction extends ActionSupport { // 印刷したいID public List<string> idList = new ArrayList<string>(); // DB更新結果フラグ public String printStatus = ""; ・・・ public String updateStatus() throws Exception { // idListを使って、DBテーブルの「印刷したよ」フラグを更新する処理・・・☆ // ☆に成功したらprintStatusに"SUCCESS"、失敗したら"FAIL"をセットする ・・・ } ・・・ }
2.printStatusの更新をチェックする
フォーム送信後、レスポンスを受け取ったときに、window.loadのイベントが呼ばれるので
そこでprintStatusの値をチェックすることにします。
jsファイル側。
$(window).load(function(){ // 印刷フラグのチェック var status = $("#printStatus"); if (!status && !status.val()) { var val = status.val(); if (val === "SUCCESS") { // 印刷フラグ更新成功ー>印刷プレビュー表示 showPrintPreview(); } else if (val === "FAIL") { // 印刷フラグ更新失敗 alert("DBの更新に失敗しました。"); } } }) function showPrintPreview() { // 印刷しない要素を非表示にする var printOff = document.getElementsByClassName("print-off"); for(var i = 0; i < printOff.length; i++) { printOff[i].style.display = "none"; } // 印刷する要素を表示する var printOn = document.getElementsByClassName("print-on"); for(var i = 0; i < printOn.length; i++) { printOn[i].style.display = "block"; } // 印刷プレビュー表示 if (isIE()) { // IEの場合 var sWebBrowserCode = '<object width="0" height="0" classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></object>'; document.body.insertAdjacentHTML( 'beforeEnd', sWebBrowserCode ); var objWebBrowser = document.body.lastChild; if(objWebBrowser == null) { return; } objWebBrowser.ExecWB( 7, 1 ); document.body.removeChild( objWebBrowser ); } else { // IE以外 window.print(); } // 印刷しない要素を再表示する for(var i = 0; i < printOff.length; i++) { printOff[i].style.display = "block"; } // 印刷する要素を非表示に戻す for(var i = 0; i < printOn.length; i++) { printOn[i].style.display = "none"; } } function isIE(){ if(!window.ActiveXObject){ if(!document.documentMode){ return false; } } return true; }
ちょっと長いですが、
印刷したい部分のみを表示する→印刷プレビューを開く→表示を元に戻す
としているだけです。
IEのみ、印刷プレビューを表示するのにActiveXObjectを使わないとうまくいかないので
そこだけポイントです。
こちらを参考にしました。
3.印刷プレビューが表示される前に、表示を戻す処理が走ってしまう
上記のjsは、試しに<s:submit>タグのonclickイベントから呼んでいたときには
期待通りに動作していましたが、いざwindow.loadから呼んでみると
印刷プレビューを表示する前に、表示を戻す処理が走ってしまうようになってしまいました。
onclickから呼ぶのと何が違うのか、まだわかってないのですが
JavaScriptは非同期処理なのですね。
[JavaScript] JavaScriptはシングルスレッド:非同期処理の仕組み | Ouka Studio
だったら、表示を戻す処理は、印刷プレビューが閉じるタイミングで実行すればいいかな。
印刷プレビューが閉じて、元画面の描画が完了すると
window.onafterprintというイベントが呼ばれるので、こちらを使います。
jsファイル側(表示を戻す処理のみ抜粋)。
var afterPrint = function() { // 印刷しない要素を表示する var printOff = document.getElementsByClassName("print-off"); for(var i = 0; i < printOff.length; i++) { printOff[i].style.display = "block"; } // 印刷する要素を非表示に戻す var printOn = document.getElementsByClassName("print-on"); for(var i = 0; i < printOn.length; i++) { printOn[i].style.display = "none"; } } // Chorome・safari if (window.matchMedia) { var mediaList = window.matchMedia('print'); mediaList.addListener(function(mql) { if (!mql.matches) { afterPrint(); } }) } // IE・Firefox window.onafterprint = afterAllPrint;
onafterprintイベントをサポートしていないブラウザもあるので
window.matchMediaを判定してごにょごにょする処理も加えておきます。
Operaはどっちもサポートしていないようです。。。困った!
(今回は、対象ブラウザじゃないのでパス)
JavaScript、いつもなんとなくで書いていたので
早急に入門しなおさなくては・・・