0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クローンした要素にもjsを適応させる

0
Posted at
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>アイテムリスト(Choices.js & Flatpickr)</title>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">

    <style>
      /* --- CSS スタイル (Flatpickr, Choices.js 用の調整は不要であればそのまま) --- */

      .c-datalist-detail {
        display: none;
        margin-left: 20px;
        border: 1px solid #ddd;
        padding: 10px;
        margin-top: 8px;
        background-color: #f9f9f9;
        border-radius: 4px;
      }
      .c-datalist-item {
        border: 1px solid #e0e0e0;
        padding: 15px;
        margin-bottom: 15px;
        background-color: #fff;
        border-radius: 6px;
      }
      .addClone {
        cursor: pointer;
        display: inline-block;
        padding: 8px 15px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        transition: background-color 0.3s;
        font-weight: bold;
      }
      .addClone:hover {
        background-color: #0056b3;
      }
      /* Choices.js が生成するラッパー要素にマージンを持たせる */
      .c-datalist-item .choices {
        display: inline-flex;
        vertical-align: middle;
        margin-right: 15px;
      }
      /* チェックボックスの配置調整 */
      .c-datalist-item > label {
        display: inline-block;
        vertical-align: middle;
      }
    </style>
  </head>
  <body>
    <div class="c-wrapper">
      <div class="c-datalist">
        
        <div class="c-datalist-item" id="original-item">
          <select name="item-select[]" class="item-select">
            <option value="1" data-detail="type1">アイテム1 (詳細あり)</option>
            <option value="2" data-detail="type2">アイテム2 (詳細あり)</option>
            <option value="3" data-detail="type3">アイテム3 (詳細あり)</option>
            <option value="4">アイテム4 (詳細なし)</option>
          </select>
          <label>
            <input type="checkbox" class="detail-checkbox" />
            **詳しく探す**
          </label>
          
          <div class="c-datalist-detail" data-detail="type1">
            Type1 の詳細入力: <input type="text" value="デフォルト値A"><br>
            日付の入力: <input type="text" class="date-input" placeholder="日付を選択 (type1)">
          </div>
          <div class="c-datalist-detail" data-detail="type2">
            Type2 の詳細入力: <input type="text" value="デフォルト値B"><br>
            日付の入力: <input type="text" class="date-input" placeholder="日付を選択 (type2)">
          </div>
          <div class="c-datalist-detail" data-detail="type3">
            Type3 の詳細入力: <input type="text" value="デフォルト値C"><br>
            日付の入力: <input type="text" class="date-input" placeholder="日付を選択 (type3)">
          </div>
        </div>

        <div class="addClone">増やす</div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
    <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/ja.js"></script>

    <script>
      // --- JavaScript ロジック ---
      document.addEventListener('DOMContentLoaded', () => {
        const dataListContainer = document.querySelector('.c-datalist');
        const addCloneButton = document.querySelector('.addClone');
        const originalItem = document.getElementById('original-item');

        // Flatpickr のデフォルト設定 (日本語化)
        const flatpickrConfig = {
          locale: flatpickr.l10ns.ja,
          allowInput: true, // 手入力も許可
        };

        // 詳細表示/非表示を切り替えるメイン関数(変更なし)
        const toggleDetail = (item) => {
          const checkbox = item.querySelector('.detail-checkbox');
          const select = item.querySelector('.item-select');
          const allDetails = item.querySelectorAll('.c-datalist-detail');

          const isChecked = checkbox.checked;
          
          // Choices.js を使用している場合、select.options から値を取得
          let selectedOption;
          if (select.choicesjs) {
              // Choices.js のインスタンスから選択された要素を取得
              const activeItems = select.choicesjs.getValue(true);
              // Choices.js は配列を返すため、単一選択の場合は最初の要素を取得
              const selectedValue = Array.isArray(activeItems) ? activeItems[0] : activeItems;
              
              // 選択された value に対応する option 要素を探す
              selectedOption = Array.from(select.options).find(opt => opt.value === selectedValue);
          } else {
              selectedOption = select.options[select.selectedIndex];
          }

          const selectedDetailType = selectedOption ? selectedOption.dataset.detail : null;

          allDetails.forEach(detail => {
            detail.style.display = 'none';
          });

          if (isChecked && selectedDetailType) {
            const targetDetail = item.querySelector(`.c-datalist-detail[data-detail="${selectedDetailType}"]`);
            if (targetDetail) {
              targetDetail.style.display = 'block';
            }
          }
        };

        // アイテムにイベントリスナーと外部ライブラリを設定する関数
        const setupItemListeners = (item) => {
          const checkbox = item.querySelector('.detail-checkbox');
          const select = item.querySelector('.item-select');
          const dateInputs = item.querySelectorAll('.date-input');

          // --- 1. Choices.js の初期化 ---
          // 既存のインスタンスを破棄する (複製後の要素用)
          if (select.choicesjs) {
            select.choicesjs.destroy();
          }
          const choices = new Choices(select, {
            searchEnabled: false, // 検索機能を無効化 (任意)
            itemSelectText: '',
          });
          // インスタンスを要素に保持させておく
          select.choicesjs = choices; 
          
          // --- 2. Flatpickr の初期化 ---
          dateInputs.forEach(input => {
            // 既存の Flatpickr インスタンスを破棄(複製後の要素用)
            if (input._flatpickr) {
              input._flatpickr.destroy();
            }
            flatpickr(input, flatpickrConfig);
          });

          // --- 3. 詳細表示ロジックの設定 ---
          
          // 初期状態を設定
          toggleDetail(item); 
          
          // イベントリスナーを設定
          checkbox.addEventListener('change', () => toggleDetail(item));
          
          // Choices.js のカスタムイベントを使用
          select.addEventListener('change', () => toggleDetail(item));
        };

        // ページロード時に最初のアイテムにリスナーを設定
        if (originalItem) {
          setupItemListeners(originalItem);
        }

        // 「増やす」ボタンのクリックイベント
        addCloneButton.addEventListener('click', () => {
          const sourceItem = document.getElementById('original-item');
          
          if (!sourceItem) {
            console.error("複製元の要素 (id='original-item') が見つかりません。");
            return;
          }

          // 【重要】複製前に Choices.js のラッパー要素を削除し、元の select 要素に戻す
          const selectToClone = sourceItem.querySelector('.item-select');
          if (selectToClone && selectToClone.choicesjs) {
            // Choices.js が生成したラッパー要素 (div.choices) を削除
            const choicesWrapper = selectToClone.closest('.choices');
            if (choicesWrapper) {
                choicesWrapper.remove();
            }
            // 元の SELECT 要素を sourceItem に戻す(cloneNodeで複製されるのは元の要素のみ)
            sourceItem.prepend(selectToClone); 
            
            // Choices.js インスタンスを破棄し、要素から参照を削除
            selectToClone.choicesjs.destroy();
            selectToClone.choicesjs = null;
          }

          // 要素を複製
          const newItem = sourceItem.cloneNode(true);

          // 複製された要素内の入力値やチェック状態をリセット
          const newSelect = newItem.querySelector('.item-select');
          const newCheckbox = newItem.querySelector('.detail-checkbox');
          const newDateInputs = newItem.querySelectorAll('.date-input');
          
          newSelect.selectedIndex = 0;
          newCheckbox.checked = false;
          // 日付入力フィールドの値をクリア
          newDateInputs.forEach(input => {
              input.value = '';
          });

          // 複製した要素にイベントリスナーとライブラリを設定
          setupItemListeners(newItem);

          // 「増やす」ボタンの直前に追加
          dataListContainer.insertBefore(newItem, addCloneButton);

          // 【重要】複製後、元の sourceItem も再初期化して Choices.js を適用し直す
          setupItemListeners(sourceItem);
        });
      });
    </script>
  </body>
</html>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?