毎日のように投稿ができるくらいにはエンジニアのお仕事に慣れてきたのかなと自惚れております金子です。
先日お仕事で、こんな感じのセレクトボックスを作成しました。

このセレクトボックス自体は、以下のURLにある通りjavascriptを使用すれば簡単に作成できるようです。
こちらのやり方では、セレクトボックスの<option></option>に設定する項目はjsで作成した配列を使っているのですが、今回私はCakePHP側で作成した配列を使っていく必要がありました。PHPの配列をjsに渡すことなんてできるのか?と思ってググっていくとこちらの記事を発見。
PHPからJavaScriptに配列を渡す / Qiita@tksninoさん
この二つの記事の方法を使わせていただくことで、無事にPHPの配列をjsに渡し、連動する2つのセレクトボックスを作成することができました!
index.ctp
<head>
<!-- selectboxで使用する都道府県と市区町村のリストをphp→jsへ -->
<?php
if(isset($prefecture)){
$prefJs=json_encode($prefecture);
}else{
$prefJs = [];
}
?>
<?php
if(isset($city)){
$cityJs=json_encode($city);
}else{
$cityJs=[];
}
?>
<script type="text/javascript">
//jsonをparseしてphpから受け取った配列をJavaScriptの変数に代入
var pref_list=JSON.parse('<?php echo $prefJs; ?>');
var city_list=JSON.parse('<?php echo $cityJs; ?>');
</script>
<?= $this->Html->script(['selectbox']) ?>
</head>
<body>
<h2>市区町村の詳細ページを検索する</h2>
<form name="searchCity">
<select id="selectPref" onchange="selPref(this);"></select>
<select id="selectCity" name="selectCity"></select>
<button class="btn_wide_thick" type="button" onclick="return search(this);">検索</button>
</form>
</body>
Controller
//phpからjsに渡す配列の形はこんなかんじです。
$prefecture = [
0 => '都道府県を選択',
1 => '北海道',
2 => '東京都',
3 => '愛知県'
];
//$cityの最初の階層が$prefectureのkeyと一致するようにしています。
//idというキーが市区町村固有のものとなっています。
$city = [
1 => [
1 => [
'id' => '',
'name' => '市区町村を選択'
],
2 => [
'id' => '1',
'name' => '函館市'
],
3 => [
'id' => '2',
'name' => '札幌市'
]
],
2 => [
1 => [
'id' => '',
'name' => '市区町村を選択'
],
2 => [
'id' => '3',
'name' => '千代田区'
],
3 => [
'id' => '4',
'name' => '足立区'
]
],
3 => [
1 => [
'id' => '',
'name' => '市区町村を選択'
],
2 => [
'id' => '5',
'name' => '名古屋市'
],
3 => [
'id' => '6',
'name' => '豊田市'
]
],
];
selectbox.js
//都道府県リストの表示
window.onload=function(){
for(var i=0;i<pref_list.length;i++){
let op = document.createElement("option");
op.value = i;
op.text = pref_list[i];
document.getElementById("selectPref").appendChild(op);
}
}
//都道府県が選択されたら市区町村を設定
function selPref(obj){
var targetArr = city_list[obj.value];
var selObj = document.getElementById('selectCity');
while(selObj.lastChild){
selObj.removeChild(selObj.lastChild);
}
for(var i=0;i<targetArr.length;i++){
let op = document.createElement("option");
op.value = targetArr[i].id;
op.text = targetArr[i].name;
selObj.appendChild(op);
}
}
//検索ボタンが押されたら、対象の市区町村詳細ページへリダイレクト
function search(){
var element = document.getElementById("selectCity");
var cityId = element.value; //選択された市町村のidを取得
if(cityId == 0){ //市町村が未選択の場合
return;
}
var url = 'http://'+location.host+'/city/detail/'+cityId;
location.href = url; //「http://example.com/city/detail/市町村ID」にリダイレクト
}
以上です!
ここでのポイントは、selectbox.jsを読み込む前に「JSON.parse」してjsで使えるようにしたphp配列を作っておくこと、のようです。
ちなみに上でご紹介した記事を読む前に自分でほいほい作ったコードだと、
北海道を選んだあとに東京都を選びなおすと、2つ目のセレクトボックスの中身に北海道の市町村が残ったままになり、その後も都道府県を選びなおすとゾンビのように市町村が増えていく事態に陥っていました……。
今後も使う機会は出てきそうなので忘れないようにメモしておきます。ついでに他の方のお役に立てれば幸いです。
金子風月
最新記事 by 金子風月 (全て見る)
- vue.jsに触ってみた話 - 2019年3月26日
- DockerでCakePHP2の開発環境を作ってみた(Mac版) - 2019年3月15日
- CakePHP3+Authコンポーネントで任意のタイミングでログインさせる処理をつくる - 2019年3月14日
なるほど、JavaScriptのほうで、PHPから受け取った配列をParseしてるんですね!
CakePHP側でJsonにパースしても良いと思います!
アプリからJSONを受け取りたい時とかによくやります。
https://qiita.com/kazu56/items/a52adb68f3bdb3313c63
はっ……Cakephp側でパースできたほうが良いですね…!
view側には出来るだけphpのコードを書きたくないので(どこに何を書いたか分からなくなる…)、このやり方のほうが好きです!
$this->viewClass = ‘Json’;のあとにview側にセットされる変数がjson形式に変換されていく感じでしょうか?
ググってみたら、これを使うと通常のビューは表示せれず真っ白な画面にjsonになったデータだけがぽつんとあるような形になるとあったので、使い方としてはコンポーネント化?しておいて、return 変数名;するイメージでしょうか。
まだまだ知らないことばかり、知るのは楽しい、ですね!
教えて下さりありがとうございます。
> これを使うと通常のビューは表示せれず真っ白な画面にjsonになったデータだけがぽつんとあるような形になる
そうです、これはjsonのみを返却するやり方です!
今表示に使っているコントローラのアクションとは、別で、json返却用のアクションを用意して使います。
いつもありがとうございます!次回はこの方法で綺麗なコードを目指したいと思います。
ありがとうございました!