第112回「WEBアプリ作成(10)(チェックボックスによる複数選択処理 1/2)」
2014.11.27
こんにちは。インストラクターの蓑島です。11月も残りわずかとなり朝晩寒くなってきましたね。
今回と次回で、Webアプリ作成の応用編として「チェックボックスによる複数選択処理」について解説します。
例えば、アプリケーションで何かの明細行があり、それらの行のいくつかを選択(つまり複数選択)して、処理を行いたい場面があります。
そんなとき各明細行にチェックボックスがついていることが多いですね。
チェックボックスは以下のHTML構文で簡単に作成できます。
<INPUT TYPE="CHECKBOX" NAME="パラメータ名" VALUE="チェック時の値">
早速、これを使った事例をみていきましょう。
ここに社員の一覧があり、複数の社員を選択し、選択した社員の給与を一律にあるパーセントだけ増額する処理を作りたいとします。
給与増額パーセントの項目に「10」と入力し、社員AさんとBさんを選択して、送信ボタンをクリックする。
そんな処理を作ってみましょう。
今回はその処理のための入力フォームだけですが、次回で更新処理のプロシージャも完成させます。
SQL> SHOW USER
ユーザーは"SCOTT"です。
1 CREATE OR REPLACE PROCEDURE EMP_MULTI_UPDATE_FORM
2 IS
3 BEGIN
4 HTP.P('<HTML>');
5 HTP.P('<HEAD><TITLE>複数選択フォーム</TITLE></HEAD>');
6 HTP.P('<BODY>');
7 HTP.P('<H2>社員複数選択処理</H2>');
8 HTP.P('<HR>');
9 HTP.P('<FORM ACTION="emp_multi_update_exe" METHOD="GET">');
10 HTP.P('<INPUT TYPE="HIDDEN" NAME="P_EMPNO" VALUE="DUMMY">'); -- 隠しパラメータ
11 HTP.P('<TABLE BORDER>');
12 HTP.P('<TR><TD>社員番号</TD><TD>社員名</TD><TD>職種</TD><TD>給与</TD><TD>選択</TD></TR>');
13 FOR REC IN (SELECT * FROM EMP ORDER BY EMPNO) LOOP --社員表から1行ずつ取り出して
14 HTP.P('<TR>'
15 || '<TD>' || REC.EMPNO||'</TD>' -- 社員番号
16 || '<TD>' || REC.ENAME ||'</TD>' -- 社員名
17 || '<TD>' || REC.JOB ||'</TD>' -- 職種
18 || '<TD>' || REC.SAL ||'</TD>' -- 給与 ↓↓ チェックボックス ↓↓
19 || '<TD><INPUT TYPE="CHECKBOX" NAME="P_EMPNO" VALUE="' || TO_CHAR(REC.EMPNO) ||'"></TD>'
20 ||'</TR>');
21 END LOOP;
22 HTP.P('</TABLE>');
23 HTP.P('選択した社員の給与を<INPUT TYPE="INPUT" NAME="P_UP" SIZE="4">%アップします。');
24 HTP.P('<BR><INPUT TYPE="SUBMIT" VALUE="送信">');
25 HTP.P('</FORM>');
26 HTP.P('</HTML>');
27* END EMP_MULTI_UPDATE_FORM;
SQL> /
プロシージャが作成されました。
では解説します。
まずこのプロシージャは、13~21行目のカーソルFORループ文(バックナンバー第10回)により、社員表(EMP表)から1行ずつ取得し、社員の一覧としてHTMLのテーブルを作成します。そのテーブルの最後の列が選択列です。(19行目)
このセル(<TD>~</TD>)の中にチェックボックスがあります。
<INPUT TYPE="CHECKBOX" NAME="P_EMPNO" VALUE="' || TO_CHAR(REC.EMPNO) ||'">
ここで、REC.EMPNOはカーソルからフェッチした行(REC)の社員番号(EMPNO)なので、仮に社員番号が7934だとすると、以下のようなチェックボックスになります。
<INPUT TYPE="CHECKBOX" NAME="P_EMPNO" VALUE="7934">
つまりこのチェックボックスにチェックして送信ボタンをクリックすると、P_EMPNO=7934 というパラメータが送信されます。
またループ処理で、チェックボックスのパラメータ名は、すべての社員で同じ名前(P_EMPNO)ですが、社員番号はそれぞれ違います。
結局、チェックボックスを複数選択すると、P_EMPNOという同じ名前のパラメータ名がそれぞれ違う社員番号の値で送信されることになります。(P_EMPNO=値1&P_EMPNO=値2・・・)
このように同じ名前のパラメータが複数送信される場合は、それを受信するプロシージャ側では、そのパラメータをコレクション型(具体的には索引付表 バックナンバー第13回)で定義する必要があります。
ではそれに関連してここで注目していただきたいのが10行目の記述です。
<INPUT TYPE="HIDDEN" NAME="P_EMPNO" VALUE="DUMMY">
すなわち、チェックボックス生成のループ処理よりも前の位置で、チェックボックスと同じ名前の隠しパラメータ(TYPE="HIDDEN")をダミーの値で記述しています。
なぜこのような記述が必要かというと、チェックボックスが一つもチェックされなかった場合のエラーを防ぐ対応なのです。
チェックボックスというのは前回(第111回)でも少し解説しましたが、チェックをしなければパラメータそのものが送信されません。
したがって、10行目のような隠しパラメータを用意しておかないと、すべてのチェックボックスがチェックされていないとき、P_EMPNOというパラメータが一つも送信されずエラーとなってしまいます。
しかし一般に、前回説明したように、パラメータは、送信されなくても受信側でそのパラメータにデフォルト値を設定すれば、エラーにならずにデフォルト値で処理が可能です。
ですが、それはコレクション型には該当しません。
パラメータにデフォルト値を指定できるのは、単純な一つの値だけをもつデータ型(スカラー型)の場合です。複数の値をもてるコレクション型ではデフォルト値は指定できません。
なぜコレクションではデフォルト値が指定できないかというと、このように考えてもらえれば良いでしょう。
まず、変数というのは値を入れる箱のようなものです。(バックナンバー第3回 変数について(その1))
スカラー型の場合は、まさに変数やパラメータを宣言したときにこのような箱が用意されるので、その箱にいれる初期値としてのデフォルト値が可能です。しかしコレクション型(索引付表)はそうではありません。コレクション型は宣言した時点では箱の数は0個です。
箱の数は割り当てる値の数に応じて宣言の「後に」用意されます。
したがってコレクションの場合は、宣言直後の初期値であるデフォルト値が意味をなさないわけです。(文法的にエラーとなります)
このようにコレクション型(索引付表)のパラメータにはデフォルト値の指定ができません。
よって対応するパラメータは最低でも一つの値が必要となります。
そのような理由があって同じパラメータ名でダミーの隠しパラメータを用意したわけです。これが10行目の記述の意味であり、チェックボックスによる複数選択処理の注意点です。
最後に話が変わって23行目ですが、この部分は解説は不要ですね。
給与の増額割合をP_UPというパラメータで送信するわけです。このパラメータは単純に1個だけですね。
では早速、このプロシージャをブラウザでリクエストして、その結果としての入力フォーム画面を表示してみましょう。
バックナンバー『第103回「WEBアプリ作成(1) (Oracle DBとPL/SQLだけで、即、WEBアプリ)」』の設定どおりであれば、以下のURLです。
http://localhost:8080/dad/emp_multi_update_form
ログインを求められたら、SCOTTユーザとパスワードを入力します。
すると、社員の一覧画面が表示されます。今回は社員番号7934と、7900の2行をチェックし、給与の増加に10(%)を入力して送信ボタンをクリックします。
送信先はemp_multi_update_exeプロシージャ(上記ソースコード 9行目)ですが、まだ作成していないので、現時点では「Not Found」エラーとなります。
また、METHOD="GET"(同 9行目)で送信しているので、URLの後ろにパラメータが確認できます。
ご覧のように、P_UP=10というパラメータの他、同じ名前(P_EMPNO)で3つのパラメータが送信されていることがわかります。たとえ、チェックボックスがすべて未選択でも、隠しパラメータで記述したP_EMPNO=DUMMY だけは必ず送信されます。
いかがでしたか? 複数選択が可能なフォーム画面の作成方法と注意点がわかりましたね。
複数選択はチェックボックスの他、MULTIPLE(複数選択可能)の指定がある選択リスト(<SELECT・・・><OPTION ・・・>)でも可能です。
しかし、すべて未選択だとやはりパラメータ自体が送信されませんので、今回と同じ隠しパラメータ(TYPE="HIDDEN")の対応が必要となります。
それでは今回はここまでにして、次回は、送信先のEMP_MULTI_UPDATE_EXEプロシージャを完成させましょう。今回のパラメータをコレクション(索引付表)のパラメータで受信しての更新処理となるわけです。
ではご期待ください。