IT系おじさんのチラシの裏
2018年10月~
当サイトの記事にはアフィリエイト広告のリンクが含まれる場合があります

JavaScriptで連動するプルダウンを選択した際に表示/非表示を切り替える

2年ほど前に「JavaScriptでプルダウンメニューを複数連動させるなるべく簡単な方法」という記事を書いたのですが、Googleの検索結果で上のほうに表示されるためかそこそこアクセス数があります。
(といっても月に400人くらい)

その記事で、うちのブログにしてはめずらしくコメントを頂いたので、はりきって回答してみたのですが、微妙に的外れな回答になってしまったようです。

コメントいわく、JavaScriptでのプルダウン選択時に要素の表示/非表示を切り替える方法が知りたいとのこと。

記事中ではOS一覧が表示される1段目のプルダウンとバージョン一覧が表示される2段目のプルダウンがあり、プルダウン1が変更されるたびにプルダウン2の中身をごっそりと入れ替えることによって連動を実現していました。

それを表示/非表示で切り替えたい、というのだから、2段目のプルダウンを非表示状態で複数列挙しておき、1段目のプルダウン変更時に連動して表示状態を切り替える方法、と思って回答したのですが、どうやらそういうことがしたいのではないようです。

プルダウンメニューで1段階目をクリック後に見えなくしたうえで、2段階目を選択するような機能を考えておりました

………!?

選択したプルダウンを消す……だと……!? そんな不可思議なUIではユーザーがびっくりしてしまうのではないかと思うのですが、プルダウンを消した後にラベル等を残す予定なのか、それとも選んだ内容をどこかにコピーして表示するのか…。何か深い事情があるのかも知れません。

ともあれ、ちょっと面白そうなので、プルダウンを選択したら、選択したプルダウンは消えて、下層プルダウンが現れるという不思議UIを作ってみることにしました。

プルダウンで選択するデータはツリー構造

まず前提となるデータを用意しなければなりません。前回はOSプルダウン、バージョンプルダウンで連動プルダウンを作成しましたが、今回はせっかくなので、もうちょい複雑に3階層くらいにしてみましょう。

都道府県とか、Amazonの商品分類とか、あるいは職種分類とか、どんなサンプルデータにしようか悩んだのですが、だんだん考えるのが面倒くさくなってきて結局記号にしてしまいました。センスなくてすみません…。

  • A
    • A-1
      • A-1-1
      • A-1-2
      • A-1-3
    • A-2
      • A-2-1
      • A-2-2
      • A-2-3
    • A-3
      • A-3-1
      • A-3-2
      • A-3-3
  • B
    • B-1
      • B-1-1
      • B-1-2
      • B-1-3
    • B-2
      • B-2-1
      • B-2-2
      • B-2-3
    • B-3
      • B-3-1
      • B-3-2
      • B-3-3
  • C
    • C-1
      • C-1-1
      • C-1-2
      • C-1-3
    • C-2
      • C-2-1
      • C-2-2
      • C-2-3
    • C-3
      • C-3-1
      • C-3-2
      • C-3-3

大分類がA、B、Cの3つで、その下層に3つずつ中分類と小分類が並ぶ感じですね。

これをプルダウンで選択するようにしてみましょう。

選択したプルダウンを消して下層プルダウンを選択させるサンプル

実行例

何はともあれ、まずは実行例です。

………………………自分で作っておいて何ですが、すげぇわかりづらい…。

プルダウンを選択した瞬間、そのプルダウンは消えて次のプルダウンが表示されるのですが、あまりに一瞬なので切り替わっているのがわかりづらいですよね。

やはり、実運用する際は選択した値をどこかに別枠で表示したほうが良さそうです。

HTML部分

単にプルダウンを並べているだけなので、クソ長いですが、やってることは単純です。

<div class="selectbox">
	<select name="top">
		<option value="">選択</option>
		<option value="op-a">A</option>
		<option value="op-b">B</option>
		<option value="op-c">C</option>
	</select>

	<select name="op-a">
		<option value="">Aグループから選択</option>
		<option value="op-a-1">A-1</option>
		<option value="op-a-2">A-2</option>
		<option value="op-a-3">A-3</option>
	</select>

	<select name="op-a-1">
		<option value="">A-1グループから選択</option>
		<option value="op-a-1-1">A-1-1</option>
		<option value="op-a-1-2">A-1-2</option>
		<option value="op-a-1-3">A-1-3</option>
	</select>

	<select name="op-a-2">
		<option value="">A-2グループから選択</option>
		<option value="op-a-2-1">A-2-1</option>
		<option value="op-a-2-2">A-2-2</option>
		<option value="op-a-2-3">A-2-3</option>
	</select>

	<select name="op-a-3">
		<option value="">A-3グループから選択</option>
		<option value="op-a-3-1">A-3-1</option>
		<option value="op-a-3-2">A-3-2</option>
		<option value="op-a-3-3">A-3-3</option>
	</select>

	<select name="op-b">
		<option value="">Bグループから選択</option>
		<option value="op-b-1">B-1</option>
		<option value="op-b-2">B-2</option>
		<option value="op-b-3">B-3</option>
	</select>

	<select name="op-b-1">
		<option value="">B-1グループから選択</option>
		<option value="op-b-1-1">B-1-1</option>
		<option value="op-b-1-2">B-1-2</option>
		<option value="op-b-1-3">B-1-3</option>
	</select>

	<select name="op-b-2">
		<option value="">B-2グループから選択</option>
		<option value="op-b-2-1">B-2-1</option>
		<option value="op-b-2-2">B-2-2</option>
		<option value="op-b-2-3">B-2-3</option>
	</select>

	<select name="op-b-3">
		<option value="">B-3グループから選択</option>
		<option value="op-b-3-1">B-3-1</option>
		<option value="op-b-3-2">B-3-2</option>
		<option value="op-b-3-3">B-3-3</option>
	</select>

	<select name="op-c">
		<option value="">Cグループから選択</option>
		<option value="op-c-1">C-1</option>
		<option value="op-c-2">C-2</option>
		<option value="op-c-3">C-3</option>
	</select>

	<select name="op-c-1">
		<option value="">C-1グループから選択</option>
		<option value="op-c-1-1">C-1-1</option>
		<option value="op-c-1-2">C-1-2</option>
		<option value="op-c-1-3">C-1-3</option>
	</select>

	<select name="op-c-2">
		<option value="">C-2グループから選択</option>
		<option value="op-c-2-1">C-2-1</option>
		<option value="op-c-2-2">C-2-2</option>
		<option value="op-c-2-3">C-2-3</option>
	</select>

	<select name="op-c-3">
		<option value="">C-3グループから選択</option>
		<option value="op-c-3-1">C-3-1</option>
		<option value="op-c-3-2">C-3-2</option>
		<option value="op-c-3-3">C-3-3</option>
	</select>
</div>

<button type="button" id="selectbox-reset">リセット</button>

<style>
.selectbox select:not(select[name=top]) {
	display:none;
}
</style>

スタイルシートではname="top"以外のselectタグを非表示にしています。

JavaScript部分

<script>
window.addEventListener('load', function () {
	//onchangeイベントの設定
	document.querySelectorAll('.selectbox select').forEach(elm => {
		elm.onchange = function () {
			let elm2 = document.getElementsByName(this.value)[0];
			if (elm2) {
				elm.style.display = 'none';
				elm2.style.display = 'block';
			}
		}
	});
	//リセットボタン
	document.getElementById('selectbox-reset').onclick = function () {
		document.querySelectorAll('.selectbox select').forEach(elm => {
			if (elm.name == 'top') {
				elm.style.display = 'block';
			} else {
				elm.style.display = 'none';
			}
			elm.selectedIndex = 0;
		});
	};
});
</script>

JavaScript部分は案外シンプルな作りでしょう?

解説

まず、スタイルシートによって、クラス名selectboxの中にあるselectタグはname=topを除いて全て非表示になっています。

そして、すべてのselectタグのonchange属性に下記のコードを埋め込むことで、自身の非表示と下層の表示を実現しています。

let elm2 = document.getElementsByName(this.value)[0];
if (elm2) {
	elm.style.display = 'none';
	elm2.style.display = 'block';
}

ここで重要なのはoptionタグのvalue属性には下層の名前を付けている点ですね。最上位のselectタグのoptionタグにはop-a/op-b/op-cという値がセットされており、同じ名前のselectタグが下層用として用意してあります。

なので、onchangeイベントが発生した際に自身のvalueでgetElementsByNameを呼び出せば、下層のプルダウンがすぐ見つけられるという仕組み。

このような作りにしておけば、いくらツリー構造を深く深くしていってもJavaScriptのコードは1ミリも変更する必要がありません。

あとリセットボタンの挙動については………詳しく説明するまでもない気もしますが………selectタグで検索して、すべてのプルダウンの選択(selectedIndex)を1番上にリセットし、name="top"の要素を表示状態に、それ以外を非表示状態にしているだけです。

まとめ

JavaScript関連でのコメントが珍しくて嬉しかったので、つい調子にのって記事にしてしまいましたが、正直需要があるのかどうかよくわかりません。

ただ、先述したとおり、「JavaScriptでプルダウンメニューを複数連動させるなるべく簡単な方法」という記事はそこそこ読まれていますし、「簡単なJavaScriptとCSSで横並びプルダウンを自作する」もたまに読まれているみたいです。

このブログは雑記ブログなのですが、Google的にはJavaScript系のブログと判定されて上位表示されているのかも知れません。謎です。

いずれにせよ、この記事のコードがどこかの誰かの参考になれば幸いです。

関連記事

JavaScriptのcanvasで縦書きを行う際の備忘録

canvas上に縦書きの文章を出力して画像化しようと考えてちょっとハマったので忘れないうちにメモしておきます。 結論から先に書くと、基本的にcanvasにはwriting-modeの設定が効くの

JavaScriptのWebAudioAPIで楽曲の口パクをしてみる

以前、ソフトウェアの解説動画を作った際、おっさんの声だけ流れてるのもアレだし、最近流行りのアバターにしゃべらせるやつやってみよう、と思ったことがあります。 vtuberとかおじさんよくわからない

コメント

  • 昨日はアドバイス頂きありがとうございました。

    今回の記事でとても勉強になりました。実を言いますとアーカイブ機能で年と月を選択する際に2段階式プルダウンを運用したく模索しておりました。

    2個のボックスで運用する方法はよく見かけますが、今回のように1つのボックスでの実装方法は調べても出てこなかったため助かりました。
    [返信]
    • なるほど年月で使う予定だったのですね。
      今回の記事が少しでもお役に立てたなら幸いです😊
      [返信]
  • 前回は、パスワード自動生成ツールの件でお世話になりありがとうございました。
    現在、JavaScriptの勉強をしているところなので
    こういった記事はとても勉強になります。
    まだテキストに書いてあるコーディングしか出来ないのがつらいところですが(汗)
    プルダウンメニュー便利そうですね。
    サイトのトップページをリニューアル中で、カテゴリー別にプルダウン使えないかなとか思っていたので、一通り本で勉強した後、こちらのコーディングも勉強してみます!
    長文失礼しました。
    [返信]
    • その節はご丁寧なコメントありがとうございました。
      使っているとコメント頂けると想像以上に嬉しいものですね😊

      JavaScriptは言語そのものは単純ですが、documentオブジェクトやスタイルシートなども一緒に学ぶ必要があるため、最初のうちはややこしく感じるかも知れません。ひとつひとつ切り分けてみると案外単純なことだったりするかも。

      ぼくもまだまだ勉強中ですが、また面白いことがあればJavaScriptの記事書いてみたいと思います。
      [返信]

新しいコメントを投稿する

[新規投稿]
 
TOP