Клонирование HTMLCollection

#javascript #html

#javascript #HTML

Вопрос:

Я пытаюсь создать форму с раскрывающимся списком основной категории и несколькими раскрывающимися списками подкатегорий, которые будут отображаться на основе выбранной основной категории. Каждая основная категория имеет только одну раскрывающуюся подкатегорию. Таким образом, это прямое соответствие между категорией и подкатегорией. Я пытаюсь использовать javascript, чтобы определить, какая категория выбрана, а затем скрыть подкатегории, не относящиеся к этому.

Я получаю все элементы подкатегории, используя имя класса. Затем я копирую элементы в новую переменную, прежде чем пытаться удалить конкретный элемент. Однако присвоение новой переменной (subCategoryList_h) не выполняется, и она остается неопределенной. Я обнаружил, что тип переменной — HTMLCollection, но я не могу понять, как ее клонировать или назначить новой переменной.

 const categoryValue = document.getElementById("category-list");
const subCategoryList = document.getElementsByClassName("sub-category");

function categoryChange() {
  console.log(categoryValue.value);
  switch (categoryValue.value) {
    case "Category_1":
      let subCategoryList_h = subCategoryList;
      subCategoryList_h.item(0).parentNode.removeChild(subCategoryList_h.item(0));
      //console.log(subCategoryList_h);
      subCategoryList_h.style.display = "none";
      break;
    case "Category_2":
      let subCategoryList_h = subCategoryList;
      subCategoryList_h.item(1).parentNode.removeChild(subCategoryList_h.item(1));
      //console.log(subCategoryList_h);
      subCategoryList_h.style.display = "none";
      break;
    case "Category_3":
      let subCategoryList_h = subCategoryList;
      subCategoryList_h.item(2).parentNode.removeChild(subCategoryList_h.item(2));
      //console.log(subCategoryList_h);
      subCategoryList_h.style.display = "none";
      break;
    case "Category_4":
      let subCategoryList_h = subCategoryList;
      subCategoryList_h.item(3).parentNode.removeChild(subCategoryList_h.item(3));
      //console.log(subCategoryList_h);
      subCategoryList_h.style.display = "none";
      break;
  }
} 
 <!doctype html lang="en">
<html lang="en">

<head>
  <!--Required meta tags-->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!--Reset Browser StyleSheet-->
  <link rel="stylesheet" type="text/css" href="css/reset.css">
  <!--Custom CSS-->
  <link rel="stylesheet" type="text/css" href="css/header_footer.css">
  <link rel="stylesheet" type="text/css" href="css/main.css">

  <title>Form</title>
</head>

<body>
  <header>
    <h1>Form</h1>
  </header>
  <main>
    <div>
      <h1>Survey</h1>
      <form name="survey">
        <div class="category" id="category">
          <label for="category">Category:</label>
          <select name="category" id="category-list" onchange="categoryChange()" required>
            <option value="Category_1">Category 1</option>
            <option value="Category_2">Category 2</option>
            <option value="Category_3">Category 3</option>
            <option value="Category_4">Category 4</option>
          </select>
        </div>

        <div id="sub-category">
          <!-- Sub-category drop down lists -->
          <div class="sub-category" id="sub-category-1">
            <label for="sub-category">Sub Category:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-2">
            <label for="sub-category">Sub Category:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-3">
            <label for="sub-category">Sub Category:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-4">
            <label for="sub-category">Sub Category:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
        </div>

      </form>
    </div>
  </main>

  <footer>
  </footer>

  <!-- JavaScript references. Do not touch -->
  <script src="scripts/survey.js" type="text/javascript"></script>
</body>

</html> 

Кроме того, если есть другие эффективные способы сделать это, пожалуйста, дайте мне знать.

Комментарии:

1. HTMLCollection не имеет style свойства. Элементы делают. Кроме того, я не понимаю, что вы пытаетесь сделать.

Ответ №1:

Некоторые проблемы, которые уже отображаются в консоли как ошибки:

  • Вы не можете объявлять одну и ту же переменную let несколько раз в одном и том же блоке (даже если в отдельных case разделах).
  • getElementsByClassName возвращает HTMLCollection, у которого нет style свойства.

Кроме того, удаление элементов, которые вы никогда не вставляете обратно, кажется плохой идеей. Вы должны только скрывать, а не удалять. Стремитесь избежать повторения кода, поэтому избегайте switch .

Ниже показано, как вы могли бы это сделать. Я не менял HTML, но, как вы можете видеть, вам не нужны многие из этих id атрибутов HTML:

 const categoryValue = document.getElementById("category-list");
const subCategoryList = document.querySelectorAll(".sub-category");

function categoryChange() {
    subCategoryList.forEach((subCategory, i) => {
        subCategory.style.display = categoryValue.selectedIndex == i ? "" : "none";
    });
}

categoryChange(); // on page load 
   <main>
    <div>
      <h1>Survey</h1>
      <form name="survey">
        <div class="category" id="category">
          <label for="category">Category:</label>
          <select name="category" id="category-list" onchange="categoryChange()" required>
            <option value="Category_1">Category 1</option>
            <option value="Category_2">Category 2</option>
            <option value="Category_3">Category 3</option>
            <option value="Category_4">Category 4</option>
          </select>
        </div>

        <div id="sub-category">
          <!-- Sub-category drop down lists -->
          <div class="sub-category" id="sub-category-1">
            <label for="sub-category">Sub Category for 1:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-2">
            <label for="sub-category">Sub Category for 2:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-3">
            <label for="sub-category">Sub Category for 3:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
          <div class="sub-category" id="sub-category-4">
            <label for="sub-category">Sub Category for 4:</label>
            <select name="sub-category">
              <option value="Sub_Category_1">Sub_Category_1</option>
              <option value="Sub_Category_2">Sub_Category_2</option>
              <option value="Sub_Category_3">Sub_Category_3</option>
              <option value="Sub_Category_4">Sub_Category_4</option>
            </select>
          </div>
        </div>

      </form>
    </div>
  </main>

  <footer>
  </footer> 

Комментарии:

1. Извините, я новичок в веб-дизайне. Я не до конца понял subCategoryList.forEach((SubCategory, i) часть. Должен ли я заменить SubCategory и i своими идентификаторами элементов и индексом?

2. Обратите внимание, что я определил subCategoryList по-другому: не с getElementsByClassName помощью , а с querySelectorAll помощью . Это современный способ сделать это. Для повторения такого списка узлов вы можете использовать .forEach . Это есть в документации . subCategory И i являются параметрами функции обратного вызова, которую я определил с помощью синтаксиса стрелки. Вы также можете использовать обычный function (subCategory, i) { , если предпочитаете. Так что ничего не менять. Вы можете увидеть, как он выполняется здесь.

3. Понял. Спасибо, что поделились файлом документации.