解答 地域マスター

前回出題した地域マスターの解答を掲載します。

地域マスターは作れたでしょうか?できるだけ解答を見ずに、市町村マスターのどこを変えれば地域マスターとして動作するようになるか、自分で考えてみてください。

いろんなプログラミングの仕方があるので、正しく動作するなら以下の解答と同じでなくてもかまいません。自分でできなかった方は解答とくらべてみてください。

【1】以下のように town.html、town.css、town.js を作成します。base.css と database.js は前回までと共通です。

town.html

<html>
  <head>
    <script type="text/javascript" src="database.js"></script>
    <script type="text/javascript" src="town.js"></script>
    <link href="base.css" rel="stylesheet" type="text/css">
    <link href="town.css" rel="stylesheet" type="text/css">
    <title>town</title>
  </head>
  <body>
    地域マスター
    <div id="prefDisplay"></div>
    <div id="cityDisplay"></div>
    <form name="form1">
      TOWN_CD:<input type="text" name="txtTownCd" id="txtTownCd">
      <a href="" name="linkMaxCd" id="linkMaxCd">最大値</a> 
      ZIP_CODE:<input type="text" name="txtZipCode" id="txtZipCode"> 
      TOWN_NAME:<input type="text" name="txtTownName" id="txtTownName"><br />
      <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="townDisplay"></div>
  </body>
</html>



town.css

#selectPref {
  width: 150px;
}

#selectCity {
  width: 150px;
}

#selectTown {
  width: 350px;
}



town.js

var txtTownCd;
var txtTownName;
var txtZipCode;
var prefCd;
var cityCd;

onload = init;
onunload = dbClose;


function init() {
  //初期設定をする関数
  txtTownCd = document.getElementById("txtTownCd");
  txtTownName = document.getElementById("txtTownName");
  txtZipCode = document.getElementById("txtZipCode");

  txtTownCd.onblur = function (){blur(this);}
  txtTownCd.onfocus = function (){focus(this);}
  txtTownName.onblur = function (){blur(this);}
  txtTownName.onfocus = function (){focus(this);}
  txtZipCode.onblur = function (){blur(this);}
  txtZipCode.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 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);
  cityDisplay();
  textClear();
  sqlDisplay("");
  document.getElementById("townDisplay").innerHTML ="";
}


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 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 cityChange(obj) {
  //市町村を選択した時の関数
  cityCd = Number(obj.value);
  townDisplay();
  textClear();
  sqlDisplay("");
}


function townDisplay() {
  //地域を表示する関数
  var mySql = "select TOWN_CD,TOWN_NAME from T03Town where CITY_CD = " + cityCd + " order by TOWN_CD" ;
  var recordSet = database.Execute(mySql);

  document.getElementById("townDisplay").innerHTML = "";

  var tempHtml = "<select size=\"25\" name=\"selectTown\" id=\"selectTown\">\n";
  while (!recordSet.EOF){
    tempHtml = tempHtml + "\t<option value=\"" + recordSet(0) + "\">" + recordSet(1) + "</option>\n";
    recordSet.MoveNext();
  }
  tempHtml = tempHtml + "</select>";

  //alert(tempHtml);
  document.getElementById("townDisplay").innerHTML = tempHtml;
  document.getElementById("selectTown").onchange = function (){townChange(this);}

  recordSet.Close();
  recordSet = null;
}


function townChange(obj) {
  //地域を選択した時の関数
  var mySql = "select TOWN_CD,ZIP_CODE,TOWN_NAME from T03Town where TOWN_CD = " + obj.value ;
  var recordSet = database.Execute(mySql);

  txtTownCd.value = recordSet(0);
  txtZipCode.value = recordSet(1);
  txtTownName.value = recordSet(2);

  recordSet.Close();
  recordSet = null;

  sqlDisplay("selectedIndex:" + obj.selectedIndex + " value:" + obj.value);
}


function dataInsert() {
  //データを追加する関数
  try{
    if(dataCheck(1)){
      var mySql = "insert into T03Town values(" + Number(txtTownCd.value) + "," + cityCd + "," + txtZipCode.value + ",'" + txtTownName.value + "')";
      sqlDisplay(mySql);
      database.Execute(mySql);
      townDisplay();
      alert("追加しました。");
    }
  }catch(error){
    alert(error.number + "\n" + error.description);
  }
}


function dataUpdate() {
  //データを更新する関数
  if(dataCheck(1)){
    var mySql = "update T03Town set ZIP_CODE =" + txtZipCode.value + ",TOWN_NAME ='" + txtTownName.value + "' where TOWN_CD = " + Number(txtTownCd.value);
    sqlDisplay(mySql);
    database.Execute(mySql);
    townDisplay();
    alert("更新しました。");
  }
}


function dataDelete() {
  //データを削除する関数
  if(dataCheck(0)){
    var mySql = "delete from T03Town where TOWN_CD = " + Number(txtTownCd.value);
    sqlDisplay(mySql);
    database.Execute(mySql);
    textClear();
    townDisplay();
    alert("削除しました。");
  }
}


function sqlDisplay(_mySql) {
  //SQLを表示する関数
  document.getElementById("sqlDisplay").innerHTML = "<p>" + _mySql + "</p>";
}


function dataCheck(flag){
  //データをチェックする関数
  var tempStr = "は必ず入力してください。";
  if (txtTownCd.value == "") {
    alert("TOWN_CD" + tempStr);
    return false;
  }
  if (txtTownCd.value.match(/[^0-9]/)) {
    alert("TOWN_CDには半角数字を入力してください!");
    txtTownCd.focus();
    return false;
  }
  if (flag == 1 && txtZipCode.value == "") {
    alert("ZIP_CODE" + tempStr);
    return false;
  }
  if (flag == 1 && txtZipCode.value.match(/[^0-9]/)) {
    alert("ZIP_CODEには半角数字を入力してください!");
    txtZipCode.focus();
    return false;
  }
  if (flag == 1 && txtTownName.value == "") {
    alert("TOWN_NAME" + tempStr);
    return false;
  }
  return true;
}


function maxCd(){
  //最大値を取得する関数
  var mySql = "select max(TOWN_CD) from T03Town";
  var recordSet = database.Execute(mySql);
  textClear();
  txtTownCd.value = recordSet(0) + 1;
  txtZipCode.focus();
  return false;
}


function textClear() {
  //テキストボックスをクリアする関数
  txtTownCd.value = "";
  txtZipCode.value = "";
  txtTownName.value = "";
}



【2】保存したら town.html をダブルクリックしてWebブラウザで開きます。
★town.html、base.css、town.css、database.js、town.js は必ず同じフォルダ内に置いてください。


【3】地域マスターが表示されました。都道府県の選択ボックスは表示されていますが、まだ市町村と地域は表示されていません。

javascript-89.gif


【4】都道府県の選択ボックスで、「東京都」を選択します。

javascript-90.gif


【5】市町村の選択ボックスが表示されました。

javascript-91.gif


【6】市町村の選択ボックスで、「港区」を選択します。

javascript-92.gif


【7】港区の地域が表示されました。

javascript-93.gif


【8】地域の選択ボックスで、「麻布十番」を選択すると、テキストボックスにデータが自動で入力されることを確認してください。

javascript-94.gif


【9】他の都道府県や市町村に切り替えたり、地域を選択して動作を確認してください。


【10】追加、更新、削除の動作も確認してください。


【解説】

大きな流れは前回の市町村マスターと同じです。関数の並びや文の順番は少し入れ替えて整理しました。

今回のポイントは絞込みが2段階になっていることです。まず都道府県を選択すると、市町村が絞り込まれます。市町村を選択すると、地域が絞り込まれます。まず主な関数の働きをつかんでください。ズバリ関数を使うメリットは、複雑な処理を関数名だけで簡単に何度でも呼び出せることです。

prefDisplay() 都道府県選択ボックスの表示、イベントハンドラの設定
prefChange() 選択ボックスの値をprefCdに保存、cityDisplay()の呼び出し
cityDisplay() 市町村選択ボックスの表示、イベントハンドラの設定
cityChange() 選択ボックスの値をcityCdに保存、cityDisplay()の呼び出し
townDisplay() 地域選択ボックスの表示、イベントハンドラの設定
townChange() テキストボックスにデータを表示

関数townChange()では、選択ボックスを切り替えたときにデータベースからデータを再度取得しています。選択ボックスの「valueにはTOWN_CD」、「textにはTOWN_NAME」が入っていますが『ZIP_CODE』がありません。そのためデータベースからTOWN_CDを抽出条件にZIP_CODEを取り出す必要があります。この方法は業務システムでよく使われますので覚えておくと便利です。

ZIP_CODEだけデータベースから取り出して、TOWN_CDとTOWN_NAMEは選択ボックスの値を使ってもかまいません。その場合は以下のSQL文になります。
var mySql = "select ZIP_CODE from T03Town where TOWN_CD = " + obj.value ;


また動かしているとテキストボックスをクリアしたほうがいいタイミングがいくつか出てきますので、共通で使う関数textClear()を新たに加えました。

function textClear() {
  //テキストボックスをクリアする関数
  txtTownCd.value = "";
  txtZipCode.value = "";
  txtTownName.value = "";
}

動作の違いはこの関数を呼び出しているところをコメントにするとよくわかります。例えば北海道から東京都に切り替えた時、市町村や地域を選択するまでテキストボックスのデータが北海道の地域のままだと都合が悪いですよね。また地域を削除した時にテキストボックスをクリアしたいこともあります。そんな時に呼び出す関数として作りました。












課題 地域マスター

理解を深めるために、課題として「地域マスター」を作ってみましょう。市町村マスターとほぼ同じプログラムで作れます。市町村マスターを参考に考えてみてください。

ポイントは絞込みが2段階になることです。まず都道府県を選択すると、市町村が絞り込まれます。さらに市町村を選択すると、地域が絞り込まれるようにしてください。

【ヒント】
テーブル名:T03Town
フィールド名:TOWN_CD、CITY_CD、ZIP_CODE、TOWN_NAME

必要なファイルは5つですが、base.css と database.js は前回までに作成したものがそのまま使えます。新たに作るのは town.html、town.css、town.js の3つです。すべて同じフォルダーに作ってください。


【手順】
・city.htmlをコピーしてtown.htmlにします。
・city.cssをコピーしてtown.cssにします。
・city.jsをコピーしてtown.jsにします。
・city.cssには各選択ボックスの横幅を指定する部分を加えます。
・divのidはprefDisplay、cityDisplayとします。
・テキストボックスのnameとidはtxtTownCd、txtZipCode、txtTownNameとします。
・選択ボックスのnameとidはselectPref、selectCity、selectTownとします。


あとは必要なところを修正して、プログラムが動くようにしてください。どこをどう変更すると動くでしょうか。


【完成図】

起動時
javascript-87.gif


動作時
javascript-88.gif







市町村マスター

今回は市町村マスターを作成します。市町村マスターの特徴は、「絞込み」です。

日本全国の市町村は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】市町村マスターが表示されました。まだ市町村は表示されていません。

javascript-82.gif


【4】都道府県の選択ボックスから「東京都」を選択します。

javascript-83.gif


【5】東京都の市町村が表示されました。

javascript-84.gif


【6】「新宿区」をクリックします。

javascript-85.gif


【7】テキストボックスCITY_CDやCITY_NAMEにデータが自動で入力されることを確認してください。

javascript-86.gif


【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を手入力で変更できると、北海道の市町村がいきなり沖縄に移動することもあります。北海道から沖縄に移動したい場合は、一度北海道側で削除して、沖縄県側で追加するような操作をしてほしいからです。

スポンサードリンク

スポンサードリンク






JavaScript初心者入門講座TOPへ