質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.78%

JavaScriptで2つのセレクトボックスを連動させたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 965

score 22

前提・実現したいこと

お世話になっております。
Laravelでフォームを作っており、DBから取得したリストを2つのセレクトボックスに表示させているのですが
一つ目のセレクトボックスを選択したらそれと関連するもののみ二つ目のセレクトボックスに表示させる動きをjQueryを使わず素のJavaScriptのみで実装したいです。
下のソースコードで言うと、corporationセレクトボックスにはgroupセレクトボックスで選択したoptionのvalueと同じgroup_idをdata-valに持つoptionのみ表示させたいです。

該当のソースコード

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<link rel="stylesheet" type="text/css" href="http://192.168.73.10/wired_admin/default.css" />
<script type="text/javascript" src="http://192.168.73.10/javascripts/vendor/prototype.js"></script>
<script type="text/javascript" src="http://192.168.73.10/javascripts/vendor/scriptaculous/scriptaculous.js"></script>
<link rel="stylesheet" type="text/css" href="http://192.168.73.10/wired_admin/themes/classic/theme.css" />
<script type="text/javascript" src="http://192.168.73.10/wired_admin/themes/classic/theme.js" charset="UTF-8"></script>
<script type="text/javascript" src="http://192.168.73.10/javascripts/application.js"></script>
<link rel="stylesheet" type="text/css" href="http://192.168.73.10/wired_admin/themes/classic/member.css" />
<title>管理システム</title>
!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> -->
<script type="text/javascript">

  Event.observe(window, 'load', function() {

  disableCoporations();
  });


  function disableCoporations() {
    if ($('p_s_service_account_group_id').value == 3 || $('p_s_service_account_group_id').value == 7) {
      $('p_m_groups').disabled = false;
      $('p_m_corporation_id').disabled = false;
    } else if ($('p_s_service_account_group_id').value == 6) {
      $('p_m_groups').disabled = false;
      $('p_m_corporation_id').disabled = true;
      $('p_m_corporation_id').value = "all";
    } else {
      $('p_m_groups').disabled = true;
      $('p_m_groups').value = "all";
      $('p_m_corporation_id').disabled = true;
      $('p_m_corporation_id').value = "all";
    }
  }

  window.addEventListener('DOMContentLoaded', function(e){
    var cl=document.querySelector('#p_m_corporation_id').cloneNode(true);
    document.querySelector('#p_m_groups').addEventListener('change',function(e){
      var t=e.target;
      [].forEach.call(document.querySelectorAll('#p_m_corporation_id option'),function(x){
        x.parentNode.removeChild(x);
      });
      [].filter.call(cl.querySelectorAll('option'),function(x){
        return x.value=="all" || t.value=="all" || x.getAttribute("data-val")==t.value;
      }).forEach(function(x){
        document.querySelector('#p_m_corporation_id').appendChild(x.cloneNode(true));
      });
    });
  });

  // $(function($) {
  //   var $corporation = $('p_m_corporation_id');
  //   var original = $corporation.html();

  //   $('#p_m_groups').change(function() {
  //     var val1 = $(this).data('val');

  //     $corporation.html(original).find('option').each(function() {
  //       var val2 = $(this).data('val');
  //       if (val1 != val2) {
  //         $(this).not(':first-child').remove();
  //       }
  //     });

  //     if ($(this).val() === '') {
  //       $corporation.attr('disabled', 'disabled');
  //     } else {
  //       $corporation.removeAttr('disabled');
  //     }

  //   });
  // });

</script>
</head>
<body class="logged_in">

<div id="container">
    <div id="main">
        <div id="content">
        <h2>新規登録</h2>
            <form method="post" action="/create_confirm">
                <table class="usual">
                    <tr> 
                        <th style="width:100px">アカウント<span class="required">*</span></th>
                        <td style="width:300px"><input type="text" name="account" value="" style="ime-mode:disabled; width: 150px;"></td>
                    </tr>
                    <tr> 
                        <th style="width:100px">ニックネーム<span class="required">*</span></th>
                        <td style="width:300px"><input type="text" name="name" value="" style="ime-mode:disabled; width: 150px;"></td>
                    </tr>
                    <tr>
                        <th>権限グループ<span class="required">*</span></th>
                        <td>
                            <select name="group" id="group" class="group">
                                <option value="all"></option>
                                <option value="0">グループなし</option>
                                <option value="1" >テストグループ1</option>
                                <option value="2" >テストグループ2</option>
                                <option value="3" >テストグループ3</option>
                                <option value="4" >テストグループ4</option>
                                <option value="5" >テストグループ4</option>
                                <option value="6" >テストグループ5</option>
                                <option value="7" >テストグループ6</option>
                                <option value="13" >テストグループ7</option>
                                <option value="14" >テストグループ8</option>
                            </select>

                            <select name="corporation" id="corporation" class="corporation">
                                <option value="all"></option>
                                <option value="584" data-val="1" >テスト法人1-1</option>
                                <option value="585" data-val="0" >テスト法人1-2</option>
                                <option value="586" data-val="1" >テスト法人2-1</option>
                                <option value="587" data-val="14" >テスト法人2-2</option>
                                <option value="588" data-val="5" >テスト法人3-1</option>
                                <option value="589" data-val="13" >テスト法人4-1</option>
                                <option value="590" data-val="6" >テスト法人4-2</option>
                                <option value="591" data-val="7" >テスト法人5-1</option>
                                <option value="592" data-val="7" >テスト法人5-2</option>
                                <option value="593" data-val="1" >テスト法人6-1</option>
                                <option value="594" data-val="2" >テスト法人6-2</option>
                            </select>
                        </td>
                    </tr>
                </table>
                <p>
                    <input type="button" value=" キャンセル " onclick="location.href='list'"> <input type="submit" value=" 登録 ">
                    <input type="hidden" name="id" value="">
                </p>    
            </form>
        </div>
    </div>
</div>
</body>
</html>

試したこと

jQueryだとこのようなコードになりました。

$(function() {
  var $corporation = $('#corporation_id');
  var original = $corporation.html();

  $('#group').change(function() {
    var val1 = $(this).data('val');

    $corporation.html(original).find('option').each(function() {
      var val2 = $(this).data('val');
      if (val1 != val2) {
        $(this).not(':first-child').remove();
      }
    });

    if ($(this).val() === '') {
      $corporation.attr('disabled', 'disabled');
    } else {
      $corporation.removeAttr('disabled');
    }

  });
});

JavaScriptで実装する方法も調べたのですが、optionをJS内で生成しているものばかりで、
グループ分けされていないリストを制御する方法が分からなかったため質問させていただきました。

初心者なので説明等分かりにくい箇所が多いかもしれませんが、ご教授頂けますと幸いです。
よろしくお願い致します。

追記:
同じテンプレート内の別の箇所でJavaScriptを使っている箇所があり、
上記jQueryをテンプレート内で実行したところそのJavaScriptも動かなくなってしまったので、
JavaScriptしか使えないのだと思いこの質問をしました。
jQueryの実行確認は別のHTMLファイルで行いました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • onakahetta

    2019/01/21 15:17

    コメントありがとうございます。
    GoogleAPIのjQueryを使おうとしていたのですが、こちらをインポートするとJavaScriptが使えなくなるようでした。インポートしている行をコメントアウトするとJavaScriptは動作するのですが、jQueryが動かなくなります。
    原因としてこういうことはあるのでしょうか?

    キャンセル

  • m.ts10806

    2019/01/21 15:22 編集

    「GoogleAPIのjQuery」が何か分かりませんが、(CDNのことだろうか・・・)
    エラーも何も出てないのでしょうか?jQuery本体がバッティングしているようにも思いますが。
    実際のコードを提示されたほうが良さそうです。(できればブラウザ表示したときのHTMLコードで)

    キャンセル

  • onakahetta

    2019/01/21 15:43 編集

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js " ></script>
    これのことです、、、呼び名が分からず申しわけございません。
    ソースコード追記します。

    キャンセル

回答 3

+2

allの仕様が書いていないのでなんと言えませんが、こうやります

<script>
window.addEventListener('DOMContentLoaded', function(e){
  var cl=document.querySelector('#corporation').cloneNode(true);
  document.querySelector('#group').addEventListener('change',function(e){
    var t=e.target;
    [].forEach.call(document.querySelectorAll('#corporation option'),function(x){
      x.parentNode.removeChild(x);
    });
    [].filter.call(cl.querySelectorAll('option'),function(x){
      return x.value=="all" || t.value=="all" || x.dataset["val"]==t.value;
    }).forEach(function(x){
      document.querySelector('#corporation').appendChild(x.cloneNode(true));
    });
  });
});
</script>
<select name="group" id="group" class="group">
    <option value="all">all</option>
    <option value="0">グループなし</option>
    <option value="1" >テストグループ1</option>
    <option value="2" >テストグループ2</option>
    <option value="3" >テストグループ3</option>
    <option value="4" >テストグループ4</option>
    <option value="5" >テストグループ4</option>
    <option value="6" >テストグループ5</option>
    <option value="7" >テストグループ6</option>
    <option value="13" >テストグループ7</option>
    <option value="14" >テストグループ8</option>
</select>

<select name="corporation" id="corporation" class="corporation">
    <option value="all">all</option>
    <option value="584" data-val="1" >テスト法人1-1</option>
    <option value="585" data-val="0" >テスト法人1-2</option>
    <option value="586" data-val="1" >テスト法人2-1</option>
    <option value="587" data-val="14" >テスト法人2-2</option>
    <option value="588" data-val="5" >テスト法人3-1</option>
    <option value="589" data-val="13" >テスト法人4-1</option>
    <option value="590" data-val="6" >テスト法人4-2</option>
    <option value="591" data-val="7" >テスト法人5-1</option>
    <option value="592" data-val="7" >テスト法人5-2</option>
    <option value="593" data-val="1" >テスト法人6-1</option>
    <option value="594" data-val="2" >テスト法人6-2</option>
</select>

disabled版

単純にcorporationのoptionのdisabledを付け替えたいだけならこう
以下のみをコピペして確認してください
(なにかに組み込むとかまずは忘れてください)

<html>
<head>
<script>
window.addEventListener('DOMContentLoaded', function(e){
  document.querySelector('#group').addEventListener('change',function(e){
    var t=e.target;
    [].forEach.call(document.querySelectorAll('#corporation option'),function(x){
      x.disabled=!(x.value=="all" || t.value=="all" || x.getAttribute("data-val")==t.value);
    });
  });
});
</script>
</head>
<body>
<select name="group" id="group" class="group">
    <option value="all">all</option>
    <option value="0">グループなし</option>
    <option value="1" >テストグループ1</option>
    <option value="2" >テストグループ2</option>
    <option value="3" >テストグループ3</option>
    <option value="4" >テストグループ4</option>
    <option value="5" >テストグループ4</option>
    <option value="6" >テストグループ5</option>
    <option value="7" >テストグループ6</option>
    <option value="13" >テストグループ7</option>
    <option value="14" >テストグループ8</option>
</select>
<select name="corporation" id="corporation" class="corporation">
    <option value="all">all</option>
    <option value="584" data-val="1" >テスト法人1-1</option>
    <option value="585" data-val="0" >テスト法人1-2</option>
    <option value="586" data-val="1" >テスト法人2-1</option>
    <option value="587" data-val="14" >テスト法人2-2</option>
    <option value="588" data-val="5" >テスト法人3-1</option>
    <option value="589" data-val="13" >テスト法人4-1</option>
    <option value="590" data-val="6" >テスト法人4-2</option>
    <option value="591" data-val="7" >テスト法人5-1</option>
    <option value="592" data-val="7" >テスト法人5-2</option>
    <option value="593" data-val="1" >テスト法人6-1</option>
    <option value="594" data-val="2" >テスト法人6-2</option>
</select>
</body>
</html>


※datasetはブラウザによって微妙なのでgetAttributeしておきました

jQuery版

$(function(){
  $('#group').on('change',function(){
    var self=$(this);
    $('#corporation option').prop('disabled',function(){
      return !(self.val()=="all" || $(this).val()=="all" || $(this).data('val')==self.val());
    });
  });
});

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/21 16:27

    ライブラリなしのピュアなjsの挙動を阻害するようなライブラリは
    害悪でしかないと思いますけどね・・・
    なんらかの形でjQueryへ置き換えを模索してください
    (もちろんライブラリなしで頑張る手もありますが)

    キャンセル

  • 2019/01/21 16:44

    そうですね、、、
    勉強の機会と思って色々と試してみます。
    お時間頂き本当にありがとうございました。

    キャンセル

  • 2019/01/21 17:59

    jQuery版まで、ありがとうございます!
    こんなにスッキリ書けるのですね。勉強になります。
    自己解決にしてしまい申し訳ないです。
    また機会があればご教授よろしくお願い致します。

    キャンセル

+1

function handler (event) {
  let val = event.target.value;
  let [first, ...opts] = document.querySelectorAll ('select[name="corporation"] option');
  let p = first.parentNode;

  ('all' === val)
  ? opts.forEach (e => e.disabled = false)
  : opts.forEach (e =>
      (e.disabled = e.getAttribute ('data-val') !== val)
      ? null
      : p.insertBefore (e, first.nextElementSibling)
    );
  first.selected = true;
}

document
  .querySelector ('select[name="group"]')
  .addEventListener ('change', handler, false);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/21 16:14

    ご回答ありがとうございます。
    頂いたコードを試したのですが、
    .addEventListener ('change', handler, false); の部分で
    Uncaught TypeError: Cannot read property 'addEventListener' of null が出てしまいます。

    キャンセル

  • 2019/01/21 16:41

    document ?

    キャンセル

check解決した方法

0

prototype.jsとjQueryの競合が原因だったようで、以下のように書き換えて動きました。

  jQuery.noConflict();

//prototype.jsのコードを記述

//jQueryのコード
  (function($) {
    $(function() {
      var $corporation = $('#corporation');
      var original = $corporation.html();

      $('#group').change(function() {
        var val1 = $(this).val();

        $corporation.html(original).find('option').each(function() {
          var val2 = $(this).data('val');
          if (val1 != val2) {
            $(this).not(':first-child').remove();
          }
        });

        if ($(this).val() === '') {
          $corporation.attr('disabled', 'disabled');
        } else {
          $corporation.removeAttr('disabled');
        }

      });
    });
  })(jQuery)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る