JavaScript: опция скрытия кода не работает в некоторых браузерах

avatar
Terry
9 августа 2021 в 04:12
91
1
0

Мои навыки работы с JavaScript довольно базовые, но я написал этот код, в котором вы выбираете из раскрывающегося списка слева (Select1) параметр, который показывает только указанные параметры в раскрывающемся списке справа ( Select2), а остальное скрывает. Я также поместил его в блокнот здесь на случай, если вы захотите повозиться. Похоже, что код работает в обеих вышеперечисленных средах в Firefox 90.0.2, но он не работает в обеих и ничего не записывает в консоль в Chrome 92.0.4515.131.

Есть идеи, почему это работает в Firefox, но не в Chrome (и других), и что я могу сделать, чтобы оно работало во всех основных браузерах.

У меня Windows 10, и я хотел бы избежать iQuery, если это целесообразно, так как я пока не хочу изучать или использовать его, поскольку я начинаю с основ.

Спасибо.

Вот код:

<!DOCTYPE html>
<html>
<head>
  <script>
    function hide_options(select_id,type)
    {
      //alert("hide_options(select_id="+select_id+", type="+type+")");
      console.log("hide_options(select_id="+select_id+", type="+type+")");
      var x = document.getElementById(select_id);
      for (i=1; i<x.options.length; i++)
      {
        x.options[i].style.display = "none";
      }
      x.options[0].selected = true;
      if (type == 'A')
      { unhide_options(select_id,"one","two") }
      if (type == 'B')
      { unhide_options(select_id,"two","three") }
      if (type == 'C')
      { unhide_options(select_id,"two") }
    }
   
    function unhide_options(select_id,...opts)
    {
      //alert("unhide_options(select_id="+select_id+"opts="+opts+")");
      console.log("unhide_options(select_id="+select_id+"opts="+opts+")");
      for (i=0; i<opts.length; i++)
      {
        document.getElementById(select_id+"_"+opts[i]).style.display = "";
      }
    }
  </script>
</head>
<body>
  <p>Selecting an option in the "Select1" dropdown should show only those options in the "Select2" dropdown.</p>
  <select name=select1>
    <option>Select1...</option>
    <option onclick="hide_options('field1','A')">Show options 1 + 2 only</option>
    <option onclick="hide_options('field1','B')">Show options 2 + 3 only</option>
    <option onclick="hide_options('field1','C')">Show option 2 only</option>
  </select>
    
  <select name=update_action id=field1>
    <option value=''>Select2...</option>
    <option value=one id=field1_one>One</option>
    <option value=two id=field1_two>Two</option>
    <option value=three id=field1_three>Three</option>
  </select>
</body>
</html>
Источник
Bravo
9 августа 2021 в 04:19
0

наиболее вероятная проблема заключается в том, что хром не запускается onclick при нажатии <option> - вы пробовали функцию console.log внутри hide_options?

Bravo
9 августа 2021 в 04:24
0

добавьте обработчик change к select и перепишите свою функцию с учетом этого

Ответы (1)

avatar
Bravo
9 августа 2021 в 04:41
1

Возможно, Chrome не генерирует событие при выборе параметра, однако вы можете использовать событие change для select

.

Я использовал атрибуты data-* для параметров, а также показываю/скрываю их в одном цикле

объект showing — это просто удобный способ настроить то, что должно отображаться, поэтому вам не нужны if/else if/else if и т. д. Я считаю, что его легче поддерживать, чем бесчисленное множество if else if`s

const selects = document.querySelectorAll('.filterer');
const showing = {
  A: ["one", "two"],
  B: ["two", "three"],
  C: ["two"]
};
selects.forEach(select => {
  select.addEventListener('change', function(e) {
    const {
      target,
      value
    } = this[this.selectedIndex].dataset;
    const show = showing[value] || [];
    const x = document.getElementById(target) || [];
    [...x]
    .slice(1)
      .forEach(option =>
        option.style.display = (show.length === 0 || show.includes(option.value)) ? '' : 'none'
      );
    if (x && x[0]) {
      x[0].selected = true;
    }
  });
});
<p>Selecting an option in the "Select1" dropdown should show only those options in the "Select2" dropdown.</p>
<select id="select1" name="select1" class="filterer">
  <option>Select1...</option>
  <option data-target='field1' data-value='A'>Show options 1 + 2 only</option>
  <option data-target='field1' data-value='B'>Show options 2 + 3 only</option>
  <option data-target='field1' data-value='C'>Show option 2 only</option>
</select>

<select name=update_action id=field1>
  <option value=''>Select2...</option>
  <option value=one id=field1_one>One</option>
  <option value=two id=field1_two>Two</option>
  <option value=three id=field1_three>Three</option>
</select>
<br/>
<hr/>
<select id="select2" name="select2" class="filterer">
  <option>Select1...</option>
  <option data-target='field2' data-value='A'>Show options 1 + 2 only</option>
  <option data-target='field2' data-value='B'>Show options 2 + 3 only</option>
  <option data-target='field2' data-value='C'>Show option 2 only</option>
</select>

<select name=update_action id=field2>
  <option value=''>Select2...</option>
  <option value=one id=field2_one>One</option>
  <option value=two id=field2_two>Two</option>
  <option value=three id=field2_three>Three</option>
</select>

Альтернатива. Вы упоминаете в комментарии, что Selects и Options создаются динамически на сервере code

Следующее позволит вам сделать это и указать видимые выборки с учетом текущего выбора, все в атрибуте option data-values

Ничто не требует жесткого кодирования в javascript таким образом

const selects = document.querySelectorAll('.filterer');
selects.forEach(select => {
  select.addEventListener('change', function(e) {
    const { target, values } = this[this.selectedIndex].dataset;
    const show = values.split(',').map(s => s.trim());
    const x = document.getElementById(target) || [];
    [...x]
    .slice(1)
      .forEach(option =>
        option.style.display = (show.length === 0 || show.includes(option.value)) ? '' : 'none'
      );
    if (x && x[0]) {
      x[0].selected = true;
    }
  });
});
<p>Selecting an option in the "Select1" dropdown should show only those options in the "Select2" dropdown.</p>
<select id="select1" name="select1" class="filterer">
  <option>Select1...</option>
  <option data-target='field1' data-values='one, two'>Show options 1 + 2 only</option>
  <option data-target='field1' data-values='two, three'>Show options 2 + 3 only</option>
  <option data-target='field1' data-values='two'>Show option 2 only</option>
</select>

<select name='update_action' id='field1'>
  <option value=''>Select2...</option>
  <option value='one' id='field1_one'>One</option>
  <option value='two' id='field1_two'>Two</option>
  <option value='three' id='field1_three'>Three</option>
</select>
<br/>
<hr/>
<br/>
<select id="select2" name="select2" class="filterer">
  <option>Select1...</option>
  <option data-target='field2' data-values='apple,banana'>Apple and banana</option>
  <option data-target='field2' data-values='banana,pineapple'>Banana and pineapple</option>
  <option data-target='field2' data-values='pineapple'>Pineapple</option>
</select>

<select name='update_action' id='field2'>
  <option value=''>Select2...</option>
  <option value='pineapple' id='field2_one'>Pineapple</option>
  <option value='banana' id='field2_two'>Banana</option>
  <option value='apple' id='field2_three'>Apple</option>
</select>

Конечно, это может потребовать изменения кода сервера, но в исходном коде была жестко закодированная логика для A B и C — этот код, код сервера может выдавать все, что ему нравится, а javascript — нет. нужно изменить

Bravo
9 августа 2021 в 05:35
1

@dmd - я давно понял, что минимальный код здесь никогда не является действительно репрезентативным ... конечно, вы можете просто использовать value="A" ... и даже не нужно иметь data-target ... но почему оригинал код имеет target? Надеюсь, я показал здесь, как добавить его в существующий HTML, который может уже иметь value и может иметь options, которые влияют на другие элементы select.

Bravo
9 августа 2021 в 05:36
1

@dMd - вы правы насчет if (x) ... должно быть if (x && x[0])

Terry
9 августа 2021 в 06:14
0

Хорошая работа, спасибо Браво! (Или я должен сказать, браво, браво!?) Мне нравится «показывающий» объект. А теперь о плохих новостях, ИЗВИНИТЕ! Я предполагаю, что сейчас не время говорить, что это урезанная версия моего исходного кода, которая может иметь десятки пар тегов <select> в зависимости от входного файла, поэтому там будут field1, field2, . ..и т.д. Продолжение в следующем комментарии...

Terry
9 августа 2021 в 06:14
0

Мой код Perl динамически генерирует необходимые пары тегов <select>, но с вашим решением мне также пришлось бы заставить его динамически создавать код JS (поскольку в нем жестко закодированы такие вещи, как «field1»), и я не делаю это где-нибудь еще в моем приложении, и я бы предпочел избегать, если это возможно. Любые предложения для решений со статическим кодом JS?

Bravo
9 августа 2021 в 06:23
0

@terry, у вас есть жестко закодированный код для условия ABC в функции - на самом деле, в моем исходном коде было столько же "жесткого кодирования", как и в вашем вопросе - так что мое редактирование сделало его менее гибким во многих отношениях, не уверен, как на самом деле код относится к коду, который вы разместили

Terry
9 августа 2021 в 06:45
0

Спасибо за редактирование. Прекрасно работает, Браво. Однако не пора ли сказать, что да, элементы A, B, C были жестко закодированы в JS, и я бы предпочел оставить все как есть, потому что эти параметры являются общими для всех правосторонних <select> . Еще раз извините! (Честно говоря, я обычно не так уж плох с масштабированием, я просто не осознавал, что мой запрос на изменение был двусмысленным.) Поэтому я предполагаю, что если вы можете каким-то образом вернуть свой «показывающий» объект обратно в JS, это было бы хорошо.

Bravo
9 августа 2021 в 06:47
0

ну, это делает код очень простым - это просто первая версия первого кода - я верну его

Terry
9 августа 2021 в 06:51
0

Хорошо, но вы все равно будете ссылаться на A, B, C в HTML, верно?

Bravo
9 августа 2021 в 06:54
0

Имеет ли смысл первый код, @Terry? потому что объект showing просто делает то же самое, что и if/else if/else if в вашем коде

Terry
9 августа 2021 в 07:03
0

Похоже, это тот стиль, который мне нужен, и исполняемый фрагмент кода работает на этом сайте так, как должен. Любые идеи, почему это не работает здесь: filestore.c1.biz/js/select2.htm

Bravo
9 августа 2021 в 07:13
2

поскольку ваш скрипт запускается до загрузки DOM — либо переместите скрипт в конец body, либо оберните скрипт в document.addEventListener('DOMContentLoaded', () => { script here })

Terry
9 августа 2021 в 08:21
0

Большое спасибо, Браво! Оба этих метода решения проблемы слишком раннего запуска скрипта работают, как показано здесь: filestore.c1.biz/js/select2a.htm и здесь: filestore.c1.biz/js /select2b.htm, пожалуйста, прибавьте зарплату!