JS（ES6）で複数のセレクトボックスの選択肢を連動させる

##はじめに

下記、select要素に親子関係を持たせる方法を、
jQueryを使わずにES6で書き直してみました。

[プラグイン不要！ jQueryで複数のセレクトボックスの選択肢を連動させる](https://try-m.co.jp/blog/web-create/936/)

## 動作確認

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="result" data-user="folium77" data-slug-hash="daJgMZ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="SELECT BOX">
  <span>See the Pen <a href="https://codepen.io/folium77/pen/daJgMZ/">
  SELECT BOX</a> by folium77 (<a href="https://codepen.io/folium77">@folium77</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## HTML

1つめのセレクトボックス。

``` html
<select id="foo" name="foo">
  <option value="" selected="selected">地方を選択</option>
  <option value="北海道・東北">北海道・東北</option>
  <option value="関東">関東</option>
  <option value="甲信越・北陸">甲信越・北陸</option>
  <option value="東海">東海</option>
  <option value="関西">関西</option>
  <option value="中国">中国</option>
  <option value="四国">四国</option>
  <option value="九州・沖縄">九州・沖縄</option>
</select>
```
２つめのセレクトボックス。
data-valに1つめのvalueに対応する値が入ります。

``` html
<select id="bar" name="bar" disabled>
  <option value="" selected="selected">都道府県を選択</option>
  <option value="北海道" data-val="北海道・東北">北海道</option>
  <option value="青森県" data-val="北海道・東北">青森県</option>
  <option value="岩手県" data-val="北海道・東北">岩手県</option>
  <option value="宮城県" data-val="北海道・東北">宮城県</option>
  <option value="秋田県" data-val="北海道・東北">秋田県</option>
  <option value="山形県" data-val="北海道・東北">山形県</option>
  <option value="福島県" data-val="北海道・東北">福島県</option>
  <option value="茨城県" data-val="関東">茨城県</option>
  <option value="栃木県" data-val="関東">栃木県</option>
  <option value="群馬県" data-val="関東">群馬県</option>
  <option value="埼玉県" data-val="関東">埼玉県</option>
  <option value="千葉県" data-val="関東">千葉県</option>
  <option value="東京都" data-val="関東">東京都</option>
  <option value="神奈川県" data-val="関東">神奈川県</option>
  <option value="新潟県" data-val="甲信越・北陸">新潟県</option>
  <option value="富山県" data-val="甲信越・北陸">富山県</option>
  <option value="石川県" data-val="甲信越・北陸">石川県</option>
  <option value="福井県" data-val="甲信越・北陸">福井県</option>
  <option value="山梨県" data-val="甲信越・北陸">山梨県</option>
  <option value="長野県" data-val="甲信越・北陸">長野県</option>
  <option value="岐阜県" data-val="東海">岐阜県</option>
  <option value="静岡県" data-val="東海">静岡県</option>
  <option value="愛知県" data-val="東海">愛知県</option>
  <option value="三重県" data-val="東海">三重県</option>
  <option value="滋賀県" data-val="関西">滋賀県</option>
  <option value="京都府" data-val="関西">京都府</option>
  <option value="大阪府" data-val="関西">大阪府</option>
  <option value="兵庫県" data-val="関西">兵庫県</option>
  <option value="奈良県" data-val="関西">奈良県</option>
  <option value="和歌山県" data-val="関西">和歌山県</option>
  <option value="鳥取県" data-val="中国">鳥取県</option>
  <option value="島根県" data-val="中国">島根県</option>
  <option value="岡山県" data-val="中国">岡山県</option>
  <option value="広島県" data-val="中国">広島県</option>
  <option value="山口県" data-val="中国">山口県</option>
  <option value="徳島県" data-val="四国">徳島県</option>
  <option value="香川県" data-val="四国">香川県</option>
  <option value="愛媛県" data-val="四国">愛媛県</option>
  <option value="高知県" data-val="四国">高知県</option>
  <option value="福岡県" data-val="九州・沖縄">福岡県</option>
  <option value="佐賀県" data-val="九州・沖縄">佐賀県</option>
  <option value="長崎県" data-val="九州・沖縄">長崎県</option>
  <option value="熊本県" data-val="九州・沖縄">熊本県</option>
  <option value="大分県" data-val="九州・沖縄">大分県</option>
  <option value="宮崎県" data-val="九州・沖縄">宮崎県</option>
  <option value="鹿児島県" data-val="九州・沖縄">鹿児島県</option>
  <option value="沖縄県" data-val="九州・沖縄">沖縄県</option>
</select>
```

## JS
```js
const foo = document.getElementById('foo');
const bar = document.getElementById('bar');
const options = bar.options;
const optionsArray = Array.from(options);
const original = bar.innerHTML;

// optionsをフィルタリング
const optionsSet = (val1) => {
  bar.innerHTML = '';

  const result = optionsArray.filter((option, i) => {
    const val2  = option.getAttribute('data-val');
    return val1 === val2 || i === 0; // 「都道府県を選択」を消さないように
  });

  for (const option of result) {
    bar.innerHTML += option.outerHTML;
  }
};

// #fooが変更されたら
foo.onchange = () => {
  bar.innerHTML = original;
  const val1 = foo.value;
  
  if (val1 !== '') {
    optionsSet(val1);
    bar.removeAttribute('disabled');
  } else {
    bar.setAttribute('disabled', 'disabled');
  } 
}
```

## 補足

### Array.from

３行目で２つめのセレクトボックスの options を取得していますが、

```js
const options = bar.options;
```

このままだと配列として扱えないので、４行目のようにして配列化。

```js
const optionsArray = Array.from(options);
```

これで filter や map が使えます。

### forEach について

jQuery の each() のように forEach で要素を消そうと下記のようにすると、

```js
  optionsArray.forEach((option, index) => {
    const val2 = option.getAttribute('data-val');
    if (val1 !== val2) {
      options.remove(index);
    }
  });
```

要素がひとつ消えるごとにインデックスがずれてしまい上手くいきません。