[勝手に解答] 市区町村データをグループ別にリスト表示

2023年2月3日

勝手に解答

eyecatch プログラミングでどうすればいいかわからない場合に、一体どうすればいいんでしょう? ググって同じ事をやっているソースコードを見つける? 質問サイトで質問をする? わかっている人に聞く? これらをやっている人は、スキルアップスピードが遅くて困っているという悩みも持っているでしょう。 個人的なこの問に対する解は、別のやり方で試すです。 全く違うやり方で、スマートに解決できてしまう事って結構多いですからね。

質問内容

サイトリンク : https://teratail.com/questions/rhk9jk8e6ef91g 質問タイトル : 都道府県と紐付けた市区町村データを複数のチェックボックスで表示したい 質問内容 :
対象のCSVデータ 上記のリンク先から標準地域コードの全国CSVをインポートし 47都道府県を階層別に表示を行いたいです。 例えば青森のチェックボックスを押下した際(cssの影響でチェックボックスが消えております)に青森内の市区町村を表示するようにしたいです。 発生している問題・エラーメッセージ 該当の都道府県を押下した際に市区町村を表示させたいのですがロジックが思い浮かびません。 該当のソースコードからアドバイスをいただきたいです。 該当のソースコード ...(以下省略)
要するに旅行サイトなどで、地区別 > 都道府県 > 市区町村のデータを階層選択させたいけど、データの処理方法と表示方法が分からないので教えて下さいという内容のようです。

解決方法

ソースコードを眺めていると、javascriptで処理をするというよりは、Laravelでのloop文記述が書かれているので、PHPでの処理になるのではないかと思ったので、質問カテゴリーが間違っているような印象も受けました。 とりあえず、csvをダウンロードして、ここからこの人と同じ環境のLaravelを構築して、この質問に書かれているソースコードと全く同じ状態に整えようとするなんて、間違ってもやりたくありません。 という事で、今回はJavascriptのみで、このような都道府県、市区町村データを処理してみたいと思います。

ソースコード

※csvデータは、dataフォルダを作って、000608358.csvというファイル名で保存しています。 <!DOCTYPE html> <html lang='ja'> <head> <meta charset='UTF-8'> <title>都道府県と紐付けた市区町村データを複数のチェックボックスで表示したい</title> <link rel='stylesheet' href='style.css'> <script src='prefs.js'></script> </head> <body> <table class='prefs'> <thead> <tr> <th>エリア</th> <th>都道府県</th> </tr> </thead> <tbody></tbody> </table> <div class='address-lists'></div> <table class='template'> <tr class='group' data-key='{{pref-group-key}}'> <td> <span>{{pref-group-name}}</span> </td> <td class='prefs'> <div class="pref"> <span data-key='{{pref-key}}'>{{pref-name}}</span> </div> </td> </tr> </table> </body> </html> html,body{ width : 100%; height : 100%; padding : 0; margin : 0; border : 0; overflow : hidden; } *, *:before, *:after { -webkit-box-sizing : border-box; -moz-box-sizing : border-box; -o-box-sizing : border-box; -ms-box-sizing : border-box; box-sizing : border-box; } .hidden, .template{ display: none; } tbody .pref > span{ cursor: pointer; } tbody .pref > span:hover{ opacity:0.5; } .address-lists{ padding:10px; border:1px dotted #ddd; border-radius:4px; margin:10px; max-height:300px; overflow-y:auto; } (()=>{ const Data = { url : './data/000608358.csv', elements : { root : null, }, template : { group : '', pref : '', }, pref_group : [ { group: '北海道', prefs: ['北海道']}, { group: '東北', prefs: ['青森','岩手','宮城','秋田','山形','福島'] }, { group: '関東', prefs: ['東京','神奈川','埼玉','千葉','茨城','栃木','群馬'] }, { group: '北陸', prefs: ['新潟','富山','石川','福井','山梨','長野'] }, { group: '東海', prefs: ['岐阜','静岡','愛知','三重'] }, { group: '近畿', prefs: ['滋賀','京都','大阪','兵庫','奈良','和歌山'] }, { group: '中国', prefs: ['鳥取','島根','岡山','広島','山口'] }, { group: '四国', prefs: ['徳島','香川','愛媛','高知'] }, { group: '九州', prefs: ['福岡','佐賀','長崎','熊本','大分','宮崎','鹿児島'] }, { group: '沖縄', prefs: ['沖縄'] } ] } function Prefs(){ this.get_templates() this.set_elemens() this.set_event() this.data_load() } Prefs.prototype.get_templates = function(){ const root = document.querySelector('.template') Data.template.pref = root.querySelector('.pref').innerHTML root.querySelector('.pref').innerHTML = '' Data.template.group = root.innerHTML } Prefs.prototype.set_elemens = function(){ Data.elements.root = document.querySelector('.prefs tbody') Data.elements.address_lists = document.querySelector('.address-lists') } Prefs.prototype.set_event = function(){ document.querySelector('table.prefs').addEventListener('click' , this.click_prefs_table.bind(this)) } Prefs.prototype.data_load = function(){ const req = new XMLHttpRequest() req.open('get' , Data.url , true); req.overrideMimeType('text/plain; charset=Shift_JIS'); req.onload = this.data_loaded.bind(this) req.send(); } Prefs.prototype.data_loaded = function(res){ const csv = res.target.response const rows = csv.split('\n') for(let i=1; i<rows.length; i++){ if(!rows[i]){continue} const cols = rows[i].split(',') const pref = cols[3].replace(/[都府県]$/,'') if(cols[1] === '0'){continue} if(!pref){continue} const group = Data.pref_group.find(e => e.prefs.indexOf(pref) !== -1) if(!group){continue} group.pref_lists = group.pref_lists ?? {} group.pref_lists[pref] = group.pref_lists[pref] ?? [] group.pref_lists[pref].push(cols.splice(4,3).join('')) } this.view() } Prefs.prototype.view = function(){ for(const group of Data.pref_group){ const group_data = { 'pref-group-key' : group.group, 'pref-group-name' : group.group, } const group_html = this.double_blancket(Data.template.group , group_data) Data.elements.root.insertAdjacentHTML('beforeend' , group_html) const pref_root = Data.elements.root.lastElementChild.querySelector('.prefs .pref') for(const pref of group.prefs){ const pref_data = { 'pref-key' : pref, 'pref-name' : pref, } const pref_html = this.double_blancket(Data.template.pref , pref_data) pref_root.insertAdjacentHTML('beforeend' , pref_html) } } } // 任意文字列の中から、{{key}}という文字列を、{key:val}で置換する処理 Prefs.prototype.double_blancket = function(str , data){ if(!str || typeof str !== 'string' || !data){return null} if(data){ const reg = new RegExp('{{(.*?)}}','g') const arr = [] let res = [] while ((res = reg.exec(str)) !== null) { arr.push(res[1]) } for(let key of arr){ const val = typeof data[key] !== 'undefined' ? data[key] : '' str = str.split('{{'+String(key)+'}}').join(val) } } return str } Prefs.prototype.click_prefs_table = function(e){ const pref_elm = e.target.closest('tbody .pref > span') if(!pref_elm){return} const pref_key = pref_elm.getAttribute('data-key') const group_elm = e.target.closest('tbody tr.group') // console.log(e.target,group_elm) const group_key = group_elm.getAttribute('data-key') const group = Data.pref_group.find(e => e.group === group_key) const lists = group.pref_lists[pref_key] this.view_lists(lists) } Prefs.prototype.view_lists = function(lists){ Data.elements.address_lists.innerHTML = '' for(const list of lists){ const div = document.createElement('div') div.textContent = list Data.elements.address_lists.appendChild(div) } } // page-onload後に発火 switch(document.readyState){ case 'complete': new Prefs() break default: window.addEventListener('load' , (()=>{new Prefs()})) break } })()

解説

まず、HTMLを大幅に書き直して、templateクラスを基準にして中身を置換する方式にしました。 csvをajaxで読み取り(Shift-jis対策済み)、事前に用意してある、Dataデータ置き場に地域グループ、都道府県別に市区町村データを格納します。 次に、事前にHTMLに記述した、tableに、地域グループと都道府県の一覧を表示。 tableにイベントをセットして、都道府県をクリックした時のみ、対象の市区町村データを拾い、下部のaddress-listsクラスに、一覧表示する仕様にしています。

あとがき

実際に本番で使いたい場合は、表示されているHTMLのデータやcssなどを、使いたいサイトの仕様に整え直して、 javascript内のイベント発火後のデータから、都道府県、市区町村の値が取れるので、その先の処理を追加するといいでしょう。 javascriptで処理したデータをphpに送りたい場合も、Ajaxを利用するといい感じに処理できますよ。 出来る限りシンプルでわかりやすくなるように、Javascriptを書いてみたので、読み解いてもらって、なんなら書き換えてもらってもいいと思います。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。