日本全国の市町村は1900件を超えますので、すべて表示するとデータが多すぎて大変です。そこで選択ボックスで選択した都道府県の市町村のみを表示するようにします。
都道府県の選択ボックスが、市町村の「抽出条件」になっているところがポイントです。この絞込みの仕組みが理解できれば、業務システムのプログラミングはかなり上達します。
実際の業務で都道府県や市町村のメンテナンスをすることはほとんどありませんが、業務システムで頻繁に使われる絞込みを学ぶには良い例だと思います。
【1】以下のようにcity.html、base.css、city.css、city.jsを新たに作成します。database.jsは前回までと共通です。
「city.html」
<html>
<head>
<script type="text/javascript" src="database.js"></script>
<script type="text/javascript" src="city.js"></script>
<link href="base.css" rel="stylesheet" type="text/css">
<link href="city.css" rel="stylesheet" type="text/css">
<title>city</title>
</head>
<body>
市町村マスター
<div id="prefDisplay"></div>
<form name="form1">
CITY_CD:<input type="text" name="txtCityCd" id="txtCityCd">
<a href="" name="linkMaxCd" id="linkMaxCd">最大値</a>
CITY_NAME:<input type="text" name="txtCityName" id="txtCityName">
<input type="button" name="btnInsert" id="btnInsert" value="追加">
<input type="button" name="btnUpdate" id="btnUpdate" value="更新">
<input type="button" name="btnDelete" id="btnDelete" value="削除">
</form>
<div id="sqlDisplay"></div>
<div id="cityDisplay"></div>
</body>
</html>
「base.css」
body {
background-color: #ccff99;
}
「city.css」
#selectPref {
width: 150px;
}
#selectCity {
width: 250px;
}
「city.js」
var txtCityCd;
var txtCityName;
var prefCd;
onload = init;
onunload = dbClose;
function init() {
//初期設定をする関数
txtCityCd = document.getElementById("txtCityCd");
txtCityName = document.getElementById("txtCityName");
txtCityCd.onblur = function (){blur(this);}
txtCityCd.onfocus = function (){focus(this);}
txtCityName.onblur = function (){blur(this);}
txtCityName.onfocus = function (){focus(this);}
document.getElementById("btnInsert").onclick = function (){dataInsert();}
document.getElementById("btnUpdate").onclick = function (){dataUpdate();}
document.getElementById("btnDelete").onclick = function (){dataDelete();}
document.getElementById("linkMaxCd").onclick = function (){return maxCd();}
dbConnect();
prefDisplay();
}
function focus(obj){
obj.style.backgroundColor = "#ffff00";
}
function blur(obj){
obj.style.backgroundColor = "#ffffff";
}
function cityDisplay() {
//データを表示する関数
var mySql = "select CITY_CD,CITY_NAME from T02City where PREF_CD = " + prefCd + " order by CITY_CD" ;
var recordSet = database.Execute(mySql);
document.getElementById("cityDisplay").innerHTML = "";
var tempHtml = "<select size=\"25\" name=\"selectCity\" id=\"selectCity\">\n";
while (!recordSet.EOF){
tempHtml = tempHtml + "\t<option value=\"" + recordSet(0) + "\">" + recordSet(1) + "</option>\n";
recordSet.MoveNext();
}
tempHtml = tempHtml + "</select>";
//alert(tempHtml);
document.getElementById("cityDisplay").innerHTML = tempHtml;
document.getElementById("selectCity").onchange = function (){cityChange(this);}
recordSet.Close();
recordSet = null;
}
function dataInsert() {
//データを追加する関数
try{
if(dataCheck(1)){
var mySql = "insert into T02City values(" + Number(txtCityCd.value) + "," + prefCd + ",'" + txtCityName.value + "')";
sqlDisplay(mySql);
database.Execute(mySql);
cityDisplay();
alert("追加しました。");
}
}catch(error){
alert(error.number + "\n" + error.description);
}
}
function dataUpdate() {
//データを更新する関数
if(dataCheck(1)){
var mySql = "update T02City set CITY_NAME ='" + txtCityName.value + "' where CITY_CD = " + Number(txtCityCd.value);
sqlDisplay(mySql);
database.Execute(mySql);
cityDisplay();
alert("更新しました。");
}
}
function dataDelete() {
//データを削除する関数
if(dataCheck(0)){
var mySql = "delete from T02City where CITY_CD = " + Number(txtCityCd.value);
sqlDisplay(mySql);
database.Execute(mySql);
cityDisplay();
alert("削除しました。");
}
}
function sqlDisplay(_mySql) {
//SQLを表示する関数
document.getElementById("sqlDisplay").innerHTML = "<p>" + _mySql + "</p>";
}
function dataCheck(flag){
//データをチェックする関数
var tempStr = "は必ず入力してください。";
if (txtCityCd.value == "") {
alert("CITY_CD" + tempStr);
return false;
}
if (txtCityCd.value.match(/[^0-9]/)) {
alert("CITY_CDには半角数字を入力してください!");
txtCityCd.focus();
return false;
}
if (flag == 1 && txtCityName.value == "") {
alert("CITY_NAME" + tempStr);
return false;
}
return true;
}
function maxCd(){
//最大値を取得する関数
var mySql = "select max(CITY_CD) from T02City";
var recordSet = database.Execute(mySql);
txtCityCd.value = recordSet(0) + 1;
txtCityName.value = "";
txtCityName.focus();
return false;
}
function cityChange(obj) {
//市町村を選択した時の関数
txtCityCd.value = obj.value;
txtCityName.value = obj.options[obj.selectedIndex].text;
sqlDisplay("selectedIndex:" + obj.selectedIndex + " value:" + obj.value);
}
function prefDisplay(obj) {
//都道府県を表示する関数
var mySql = "select * from T01Prefecture order by PREF_CD";
var recordSet = database.Execute(mySql);
document.getElementById("prefDisplay").innerHTML = "";
var tempHtml = "<select name=\"selectPref\" id=\"selectPref\">\n";
while (!recordSet.EOF){
tempHtml = tempHtml + "\t<option value=\"" + recordSet(0) + "\">" + recordSet(1) + "</option>\n";
recordSet.MoveNext();
}
tempHtml = tempHtml + "</select>";
//alert(tempHtml);
document.getElementById("prefDisplay").innerHTML = tempHtml;
document.getElementById("selectPref").onchange = function (){prefChange(this);}
recordSet.Close();
recordSet = null;
}
function prefChange(obj) {
//都道府県を選択した時の関数
prefCd = Number(obj.value);
sqlDisplay("");
cityDisplay();
}
【2】保存したら city.html をダブルクリックしてWebブラウザで開きます。
★city.html、base.css、city.css、database.js、city.jsは必ず同じフォルダ内に置いてください。
【3】市町村マスターが表示されました。まだ市町村は表示されていません。
【4】都道府県の選択ボックスから「東京都」を選択します。
【5】東京都の市町村が表示されました。
【6】「新宿区」をクリックします。
【7】テキストボックスCITY_CDやCITY_NAMEにデータが自動で入力されることを確認してください。
【8】他の都道府県に切り替えたり、市町村を選択して動作を確認してください。
【9】追加、更新、削除の動作も確認してください。
【解説】
html側では、JavaScriptのファイルを2つ、CSSのファイルを2つ読み込んでいます。このように複数のファイルに分割して記述し、読み込むことができます。
<script type="text/javascript" src="database.js"></script>
<script type="text/javascript" src="city.js"></script>
<link href="base.css" rel="stylesheet" type="text/css">
<link href="city.css" rel="stylesheet" type="text/css">
今回CSSファイルを base.css と city.css に分離しました。背景色などのシステム全般に関わるデザインはbase.cssに記載して共通化します。共通化することでデザインを一気に変えることができます。
個々のデザインに関するCSSを分離することで、他のファイルに同じ名前のidがあっても影響しないようにしました。例えば都道府県マスターと市町村マスターに selectPref という同じidの部品があったとすると、同じCSSを参照している場合、大きさが同じになります。しかし大きさを変えたいこともあるはずです。そんな時は個々のCSSで指定していたほうが便利です。
またhtmlには都道府県の選択ボックスを表示するタグはなく、場所をdivでマークしているだけです。選択ボックスはプログラムで表示しています。
<div id="prefDisplay"></div>
JavaScript側は都道府県マスターとほとんど同じ仕組みです。追加したのは絞込みによる機能です。
まず変数prefCdは共通で使うので関数の外で宣言しています。
var prefCd;
関数init()の中でprefDisplay()を呼び出しています。
function init() {
省略
prefDisplay();
}
prefDisplay()の中では、データベースからデータを取得して、都道府県の選択ボックスを作成しています。sizeを書かないと1件だけ表示されます。選択ボックス作成後にイベントハンドラを設定して、選択ボックスの値が変わった時(onchange)に、関数prefChange(this)を呼び出すようにしています。thisは選択ボックス自身の参照です。
document.getElementById("selectPref").onchange = function (){prefChange(this);}
呼び出された関数prefChange(obj)では、objに選択ボックスの参照(this)が入っています。
選択ボックスで選択した都道府県のCDを変数prefCdに代入します。
prefCd = Number(obj.value);
SQLを表示する部分を空白にします。
sqlDisplay("");
関数cityDisplay()を呼び出し、市町村を表示します。
cityDisplay();
関数cityDisplay()の中を見てみましょう。重要なのは以下の1行です。
var mySql = "select CITY_CD,CITY_NAME from T02City where PREF_CD = " + prefCd + " order by CITY_CD" ;
関数prefChange()で代入した変数prefCdが抽出条件になっていますね。これが選択した都道府県の市町村だけを表示している仕組みです。
あとはイベントハンドラを設定して、市町村を選択した時にテキストボックスに表示する関数cityChange()を呼び出しています。
関数cityChange()にある以下の文ですが、通常SQL文を引数にしていますが、文字列と式を引数にして確認用に表示しています。式が評価された値が文字列と結合して引数になります。
sqlDisplay("selectedIndex:" + obj.selectedIndex + " value:" + obj.value);
こういう書き方もできるんだな程度でかまいません。不要ならコメントにするか、削除してください。
テーブルT02Cityにはフィールドが3つあります。CITY_CD、PREF_CD、CITY_NAMEです。ユーザーが入力できるのは、CITY_CDとCITY_NAMEです。
PREF_CDはユーザーが都道府県の選択ボックスをチェンジした時に自動で変数prefCdに代入されるので、追加時は変数の値を使っています。ユーザーが手入力で値を変更できないようにしているのです。また更新時にもPREF_CDは更新できません。
理由はユーザーがPREF_CDを手入力で変更できると、北海道の市町村がいきなり沖縄に移動することもあります。北海道から沖縄に移動したい場合は、一度北海道側で削除して、沖縄県側で追加するような操作をしてほしいからです。