ボタンを押すと計算を実行していましたが、これを個数の入力と同時に自動的に計算結果が表示されるように改良します。
また、価格の部分は勝手に変更されては困るので、変更できないようにします。個数には、半角数字しか入力できないように制限を加えます。
実例(p7-3.html)
個数を入力したときに自動的に計算を実行します。
個数は<input>タグに入力されるので、これが変更されたときに発生するイベント処理を行います。「onChange」を使います。
下記の表示は3行分ですが、10行全てに追加してください。以下、フォームの仕様変更は同様に作業します。
<tr>
<td>S001</td>
<td><a href="s001.html" class="t_name" target="_blank">サクラソフトクリーム</a></td>
<td><input type="text" class="price" id="s001" value="200" size="10" maxlength="5"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>S002</td>
<td><a href="s002.html" class="t_name" target="_blank">さくらかき氷</a></td>
<td><input type="text" class="price" id="s002" value="350" size="10" maxlength="5"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>W001</td>
<td><a href="w001.html" class="t_name" target="_blank">あんこぼたもち</a></td>
<td><input type="text" class="price" id="w001" value="180" size="10" maxlength="5"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
内容の変更時に、ユーザー関数calc_number()を呼び出します。このとき、ID名を一緒に送っているのは、後で戻ってくる値を受け取るためです。このとき、「calc_number("s001")」などとID名を書かずに「this.id」を使っています。これは、コピーをする作業を簡便にするための方法です。できるだけ、書き直しをせずにコピーできる方が間違いも防ぐことができるのです。
では、対応するユーザー関数を<script>タグ内に記述しましょう。
function calc_number(s) {
var t;
t = document.getElementById(s).value;
if (t.match(/[^0-9]/g)) {
alert("半角数字だけを入力してください。");
document.getElementById(s).value = "";
} else {
calc_price();
}
}
ユーザー関数では変数sに元のID名が入ってます。
そこで変数tには、IDを参照して値を取り出したり、値を空欄にして戻しています。
if文では、個数の入力値を調べて、半角の数字だけが入力されたかどうか確認をしています。それが命令文のmatch()です。ここでは正規表現という仕組みを使っています。//で挟まれた「[^0-9]」が正規表現で、入力値(変数t)が0~9までの文字(数値ではなく文字列の構成要素)以外にないことを検査(マッチング)しています。
もし、半角数字以外の文字が入っているとif文は真となり、警告を表示し、<input>タグの値を空欄に戻します。偽の場合はユーザー関数calc_price()を呼び出して合計金額を計算します。
動作確認をする時は、半角数字を入力した後、フォーカスを移動させないとonChangeが発生しません。フォーカスの移動とは、カーソルの移動でもあり、tabキーを押したり、マウスで別の場所をクリックします。
また、わざと文字を入力して、alert()が機能することも確認します。
このように、プログラムが完成したら、正しい動作だけでなく、誤った動作も試しておくと、利用者が想定外のことを行ったとしても、それに対処しておくことができます。
フォーム内の価格を変更されると困るので、これを禁止します。
起動時に価格を配列変数に取得していますので、変更が発生したら元の数字に戻します。
まずはフォーム内の<input>タグにイベント処理を追加します。ここでも10行分の作業をしてください。
<tr>
<td>S001</td>
<td><a href="s001.html" class="t_name" target="_blank">サクラソフトクリーム</a></td>
<td><input type="text" class="price" id="s001" value="200" size="10" maxlength="5" onChange="reprice(this.id)"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>S002</td>
<td><a href="s002.html" class="t_name" target="_blank">さくらかき氷</a></td>
<td><input type="text" class="price" id="s002" value="350" size="10" maxlength="5" onChange="reprice(this.id)"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>W001</td>
<td><a href="w001.html" class="t_name" target="_blank">あんこぼたもち</a></td>
<td><input type="text" class="price" id="w001" value="180" size="10" maxlength="5" onChange="reprice(this.id)"></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
変更時のイベント処理が追加できたら、ユーザー関数reprice()を作りましょう。
function reprice(s) {
document.getElementById(s).value = sprice[s];
alert("価格は変更できません。");
}
非常にシンプルな内容で、変数sにイベント発生場所のID名を受け取っています。
すぐさま発生場所に配列変数spriceの内容を返しています。
価格を変更して動作確認をしましょう。
<input>タグに属性「readonly」を設定することで書き換えを禁止することができます。
ただし、古いブラウザなど対応しない場合もあります。2つの設定を二重にしておいても良いでしょう。
<tr>
<td>S001</td>
<td><a href="s001.html" class="t_name" target="_blank">サクラソフトクリーム</a></td>
<td><input type="text" class="price" id="s001" value="200" size="10" maxlength="5" readonly></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>S002</td>
<td><a href="s002.html" class="t_name" target="_blank">さくらかき氷</a></td>
<td><input type="text" class="price" id="s002" value="350" size="10" maxlength="5" readonly></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
<tr>
<td>W001</td>
<td><a href="w001.html" class="t_name" target="_blank">あんこぼたもち</a></td>
<td><input type="text" class="price" id="w001" value="180" size="10" maxlength="5" readonly></td>
<td><input type="text" class="number" size="5" maxlength="3" onChange="calc_number(this.id)"></td>
</tr>
こちらの場合、書き戻しがいらないので、ユーザー関数は不要です。
スクリプトの場合と違い、こちらでは注意を促すメッセージを表示することができません。重要なメッセージを伝えたい場合は、スクリプトを使う方が良いでしょう。
配列変数snumberに関する処理を一部変更します。
というのも、フォームから毎回全ての数値を調べてくるよりも、値の入力時に配列変数を入れ換えて置いて、計算時には再度の確認作業をなくしてしまいます。その方が少しでも計算の速度があがるはずです。
まずは、配列変数calc_number()に1行追加します。赤字の箇所です。
function calc_number(s) {
var t;
t = document.getElementById(s).value;
if (t.match(/[^0-9]/g)) {
alert("半角数字だけを入力してください。");
document.getElementById(s).value = "";
} else {
snumber[s] = eval(t);
calc_price();
}
}
次に配列変数calc_price()から青字の箇所を削除します。
function calc_price() {
var n;
tprice = 0;
for (n=0;n<sid.length;n++) {
snumber[sid[n]+"n"] = document.getElementById(sid[n] + "n").value;
tprice += sprice[sid[n]] * snumber[sid[n]+"n"];
}
//合計金額
document.getElementById("total_price").innerHTML = tprice + "円";
}
これで、データの移し替えは入力時に一度だけ行われ、計算時には行われなくなります。
削除した部分と書き加えた部分は同じことをしています。
ユーザー関数calc_number()では、IDを元にvalueの値を一旦変数tに入れてから、追加の部分でそれを配列変数snumberに入れています。二カ所で処理していますが、1つにまとめると、削除した部分と同じになるのです。
些細な違いではありますが、for文の中で毎回全ての数値を調べるということは、処理が大きくなったときに影響が見えてきます。普段から時間の節約を念頭に置いてスクリプトを書くことは重要です。ただし、プログラムの単純さも見直し作業の簡便さに繋がるため、プログラムの目的に応じて選択しましょう。