Как изменить значение тега HTML по умолчанию на основе пользовательской опции ?

#javascript #html #jquery

#javascript #HTML #jquery

Вопрос:

Я пытаюсь изменить свое значение <select><option value=""></option></select> на основе созданной мной пользовательской опции выбора. Поскольку параметры выбора не могут быть настроены так легко, мы используем JS, jQuery для его настройки. Поскольку я плохо разбираюсь в JS, я просто искал видео и сделал то же самое, чтобы изменить свой вариант выбора. Теперь проблема в том, что когда я выбираю опцию из опции пользовательского выбора, значение исходной опции выбора не меняется, и из-за этого я не могу отправить свои данные формы.

Вот опция выбора по умолчанию

 <label for="id_product">Product</label>
    
            <div class="card my-5">

                <div class="card-body">

                    <div class="select-menu my-5">
    
                        <select name="product" class="custom-select product-select" id="id_product">
            
                            <option value="" selected="">---------</option>
            
                            <option value="3">Test Product 2</option>
            
                            <option value="2">Test Product 1</option>
            
                            <option value="1">Test Product</option>
            
                        </select>
            
                    </div>

                </div>

            </div>
  

Вот пользовательский, созданный с помощью js

 <div class="card my-5">

                <div class="card-body">

                    <div class="dropdown">
                
                        <div class="dropdown__selected">---------</div>
                        
                        <div class="dropdown__menu">
                            
                            <input placeholder="Search..." type="text" class="dropdown__menu_search">
                            
                            <div class="dropdown__menu_items">
                                
                                <div class="dropdown__menu_item selected" data-value="">---------</div>
                                
                                <div class="dropdown__menu_item" data-value="3">Test Product 2</div>
                                
                                <div class="dropdown__menu_item" data-value="2">Test Product 1</div>
                                
                                <div class="dropdown__menu_item" data-value="1">Test Product</div>
                            
                            </div>
                        
                        </div>
                    
                    </div>

                </div>

            </div>
  

JS-код для отображения вышеупомянутой пользовательской опции выбора

 const dropdowns = document.querySelectorAll('.select-menu, #id_weight_1');

const form = document.querySelector('form')

if(dropdowns.length > 0){
    dropdowns.forEach(dropdown => {
        createCustomDropdown(dropdown);
    });
}

// if(form !=null){
//     form.addEventListener('submit', (e) => {
//         e.preventDefault();
//         const a = form.querySelector('[name=product]');
//         console.log('Select:', a.options[a.selectedIndex].text);
//     });
// }

// Create custom dropdown
function createCustomDropdown(dropdown) {
    // Get all options and convert them from nodelist to array
    const options = dropdown.querySelectorAll('option');
    const optionsArr = Array.prototype.slice.call(options);
  
    // Create custom dropdown element and add class dropdown to it
    // Insert it in the DOM after the select field
    const customDropdown = document.createElement('div');
    customDropdown.classList.add('dropdown');
    dropdown.insertAdjacentElement('afterend', customDropdown);
  
    // Create element for selected option
    // Add class to this element, text from the first option in select field and append it to custom dropdown
    const selected = document.createElement('div');
    selected.classList.add('dropdown__selected');
    selected.textContent = optionsArr[0].textContent;
    customDropdown.appendChild(selected);
  
    // Create element for dropdown menu, add class to it and append it to custom dropdown
    // Add click event to selected element to toggle dropdown menu
    const menu = document.createElement('div');
    menu.classList.add('dropdown__menu');
    customDropdown.appendChild(menu);
    selected.addEventListener('click', toggleDropdown.bind(menu));
  
    // Create serach input element
    // Add class, type and placeholder to this element and append it to menu element
    const search = document.createElement('input');
    search.placeholder = 'Search...';
    search.type = 'text';
    search.classList.add('dropdown__menu_search');
    menu.appendChild(search);
  
    // Create wrapper element for menu items, add class to it and append to menu element
    const menuItemsWrapper = document.createElement('div');
    menuItemsWrapper.classList.add('dropdown__menu_items');
    menu.appendChild(menuItemsWrapper);    
  
    // Loop through all options and create custom option for each option and append it to items wrapper element
    // Add click event for each custom option to set clicked option as selected option
    optionsArr.forEach(option => {
      const item = document.createElement('div');
      item.classList.add('dropdown__menu_item');
      item.dataset.value = option.value;
     
      item.textContent = option.textContent;
      menuItemsWrapper.appendChild(item);
  
      item.addEventListener('click', setSelected.bind(item, selected, dropdown, menu));
    });
  
    // Add selected class to first custom option
    menuItemsWrapper.querySelector('div').classList.add('selected');
  
    // Add input event to search input element to filter items
    // Add click event to document element to close custom dropdown if clicked outside of it
    // Hide original dropdown(select)
    search.addEventListener('input', filterItems.bind(search, optionsArr, menu));
    document.addEventListener('click', closeIfClickedOutside.bind(customDropdown, menu));
    // dropdown.style.display = 'none';
  }
  
  // Toggle dropdown
  function toggleDropdown() {
    // Check if dropdown is opened and if it is close it, otherwise open it and focus search input
    if(this.offsetParent !== null) {
      this.style.display = 'none';
    }else {
      this.style.display = 'block';
      this.querySelector('input').focus();
    }
  }
  
  // Set selected option
  function setSelected(selected, dropdown, menu) {
    // Get value and label from clicked custom option
    const value = this.dataset.value;
    
    const label = this.textContent;const th = 
  
    // Change the text on selected element
    // Change the value on select field
    selected.textContent = label;
    dropdown.value = value;
  
    // Close the menu
    // Reset search input value
    // Remove selected class from previously selected option and show all divs if they were filtered
    // Add selected class to clicked option
    menu.style.display = 'none';
    menu.querySelector('input').value = '';
    menu.querySelectorAll('div').forEach(div => {
      if(div.classList.contains('selected')) {
        div.classList.remove('selected');
      }
      if(div.offsetParent === null) {
        div.style.display = 'block';
      }
    });
    this.classList.add('selected');
    
  }
  
  // Filter items
  function filterItems(itemsArr, menu) {
    // Get all custom options
    // Get the value of search input and convert it to all lowercase characters
    // Get filtered items
    // Get the indexes of filtered items
    const customOptions = menu.querySelectorAll('.dropdown__menu_items div');
    const value = this.value.toLowerCase();
    
    const filteredItems = itemsArr.filter(item => item.label.toLowerCase().includes(value));
    const indexesArr = filteredItems.map(item => itemsArr.indexOf(item));
  
    // Check if option is not inside indexes array and hide it and if it is inside indexes array and it is hidden show it
    itemsArr.forEach(option => {
      if(!indexesArr.includes(itemsArr.indexOf(option))) {
        customOptions[itemsArr.indexOf(option)].style.display = 'none';
      }else {
        if(customOptions[itemsArr.indexOf(option)].offsetParent === null) {
          customOptions[itemsArr.indexOf(option)].style.display = 'block';
        }
      }
    });
  }
  
  // Close dropdown if clicked outside dropdown element
  function closeIfClickedOutside(menu, e) {
    if(e.target.closest('.dropdown') === null amp;amp; e.target !== this amp;amp; menu.offsetParent !== null) {
      menu.style.display = 'none';
    }
}
  

Как и здесь, у нас есть tow select options, #taxes значение изменяется на основе значения #invoice . Аналогичным образом я хочу, чтобы моя опция выбора работала подобным образом, поскольку у меня есть одна опция выбора, а пользовательская состоит из элементов div. Я надеюсь, вы не будете возражать, отвечая на мой вопрос, я действительно плохо разбираюсь в js, пожалуйста, помогите!

 <select id="invoice">

    <option value="no" selected>no invoice</option>

    <option value="invoice-type-1">invoice type 1</option>

    <option value="invoice-type-2">invoice type 2</option>

</select>

<select id="taxes">

    <option value="0"> tax free</option>

    <option value="19"> apply 19%</option>

</select>
  
 $('#invoice').change(function(){
    if($(this).val()=='no')
        $('#taxes').val('0');
    else
        $('#taxes').val('19');
});

  

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

1. вы можете сделать выбранный выбор / опцию на основе значения, вы не можете сделать выбранный div таким.

2. @DevsiOdedra На самом деле я тебя не понял. Выбранный div изменяется в зависимости от выбранного мной параметра. Когда я выбираю опцию из выпадающих элементов, я хочу, чтобы исходное значение тега select было соответствующим образом изменено.

3. @DevsiOdedra Как вы говорите, мне все равно не нужно, чтобы это работало? Я хочу использовать пользовательскую опцию выбора, например, если у нас есть 1000 опций, прокручивающих все из них, и выбор опции будет намного сложнее, верно

4. хорошо, на основе пользовательского выпадающего списка вы хотите создать selected Productdropdown

5. @DevsiOdedra На основе пользовательского выпадающего списка я также хочу, чтобы он выбирал значение параметра выбора по умолчанию. Я имею в виду, что когда я выбираю тестовый продукт 1 из data-value="1" пользовательского выпадающего списка, я хочу, чтобы он автоматически выбирал тестовый продукт 1 из опции выбора по умолчанию, которая имеет value="1" , чтобы я мог отправить данные формы.

Ответ №1:

Смотрите, как показано ниже, выбор на основе пользовательского выпадающего списка

 const dropdowns = document.querySelectorAll('.select-menu, #id_weight_1');

const form = document.querySelector('form')

if(dropdowns.length > 0){
    dropdowns.forEach(dropdown => {
        createCustomDropdown(dropdown);
         
    });
}

// if(form !=null){
//     form.addEventListener('submit', (e) => {
//         e.preventDefault();
//         const a = form.querySelector('[name=product]');
//         console.log('Select:', a.options[a.selectedIndex].text);
//     });
// }

// Create custom dropdown
function createCustomDropdown(dropdown) {
    
    // Get all options and convert them from nodelist to array
    const options = dropdown.querySelectorAll('option');
    const optionsArr = Array.prototype.slice.call(options);
  
    // Create custom dropdown element and add class dropdown to it
    // Insert it in the DOM after the select field
    const customDropdown = document.createElement('div');
    customDropdown.classList.add('dropdown');
    dropdown.insertAdjacentElement('afterend', customDropdown);
  
    // Create element for selected option
    // Add class to this element, text from the first option in select field and append it to custom dropdown
    const selected = document.createElement('div');
    selected.classList.add('dropdown__selected');
    selected.textContent = optionsArr[0].textContent;
    customDropdown.appendChild(selected);
  
    // Create element for dropdown menu, add class to it and append it to custom dropdown
    // Add click event to selected element to toggle dropdown menu
    const menu = document.createElement('div');
    menu.classList.add('dropdown__menu');
    customDropdown.appendChild(menu);
    selected.addEventListener('click', toggleDropdown.bind(menu));
  
    // Create serach input element
    // Add class, type and placeholder to this element and append it to menu element
    const search = document.createElement('input');
    search.placeholder = 'Search...';
    search.type = 'text';
    search.classList.add('dropdown__menu_search');
    menu.appendChild(search);
  
    // Create wrapper element for menu items, add class to it and append to menu element
    const menuItemsWrapper = document.createElement('div');
    menuItemsWrapper.classList.add('dropdown__menu_items');
    menu.appendChild(menuItemsWrapper);    
  
    // Loop through all options and create custom option for each option and append it to items wrapper element
    // Add click event for each custom option to set clicked option as selected option
    optionsArr.forEach(option => {
      const item = document.createElement('div');
      item.classList.add('dropdown__menu_item');
      item.dataset.value = option.value;
     
      item.textContent = option.textContent;
      menuItemsWrapper.appendChild(item);
  
      item.addEventListener('click', setSelected.bind(item, selected, dropdown, menu));
      
     
    });
  
    // Add selected class to first custom option
    menuItemsWrapper.querySelector('div').classList.add('selected');
  
    // Add input event to search input element to filter items
    // Add click event to document element to close custom dropdown if clicked outside of it
    // Hide original dropdown(select)
    search.addEventListener('input', filterItems.bind(search, optionsArr, menu));
    document.addEventListener('click', closeIfClickedOutside.bind(customDropdown, menu));
    // dropdown.style.display = 'none';
  }
  
  // Toggle dropdown
  function toggleDropdown() {
    // Check if dropdown is opened and if it is close it, otherwise open it and focus search input
    if(this.offsetParent !== null) {
      this.style.display = 'none';
    }else {
      this.style.display = 'block';
      this.querySelector('input').focus();
    }
  }
  
  // Set selected option
  function setSelected(selected, dropdown, menu) {
    // Get value and label from clicked custom option
    const value = this.dataset.value;
    
    console.log(value);
    document.getElementById("id_product").selectedIndex = value;
    const label = this.textContent;const th = 
  
    // Change the text on selected element
    // Change the value on select field
    selected.textContent = label;
    dropdown.value = value;
  
    // Close the menu
    // Reset search input value
    // Remove selected class from previously selected option and show all divs if they were filtered
    // Add selected class to clicked option
    menu.style.display = 'none';
    menu.querySelector('input').value = '';
    menu.querySelectorAll('div').forEach(div => {
      if(div.classList.contains('selected')) {
        div.classList.remove('selected');
      }
      if(div.offsetParent === null) {
        div.style.display = 'block';
      }
    });
    this.classList.add('selected');
    
  }
  
  // Filter items
  function filterItems(itemsArr, menu) {
    // Get all custom options
    // Get the value of search input and convert it to all lowercase characters
    // Get filtered items
    // Get the indexes of filtered items
    const customOptions = menu.querySelectorAll('.dropdown__menu_items div');
    const value = this.value.toLowerCase();
    
    const filteredItems = itemsArr.filter(item => item.label.toLowerCase().includes(value));
    const indexesArr = filteredItems.map(item => itemsArr.indexOf(item));
  
    // Check if option is not inside indexes array and hide it and if it is inside indexes array and it is hidden show it
    itemsArr.forEach(option => {
      if(!indexesArr.includes(itemsArr.indexOf(option))) {
        customOptions[itemsArr.indexOf(option)].style.display = 'none';
      }else {
        if(customOptions[itemsArr.indexOf(option)].offsetParent === null) {
          customOptions[itemsArr.indexOf(option)].style.display = 'block';
        }
      }
    });
  }
  
  // Close dropdown if clicked outside dropdown element
  function closeIfClickedOutside(menu, e) {
    if(e.target.closest('.dropdown') === null amp;amp; e.target !== this amp;amp; menu.offsetParent !== null) {
      menu.style.display = 'none';
    }
}  
 <label for="id_product">Product</label>
    
            <div class="card my-5">

                <div class="card-body">

                    <div class="select-menu my-5">
    
                        <select name="product" class="custom-select product-select" id="id_product">
            
                            <option value="" selected="">---------</option>
            
                            <option value="3">Test Product 2</option>
            
                            <option value="2">Test Product 1</option>
            
                            <option value="1">Test Product</option>
            
                        </select>
            
                    </div>

                </div>

            </div>  

Ответ №2:

Я не знаю, почему вы настаиваете на том, чтобы в качестве вашего второго виджета было выбрано «пользовательское» поле выбора. Вы можете упростить жизнь, если используете стандартное поле выбора и синхронизируете первое, выполнив что-то простое, как показано ниже:

 document.getElementById('id_custom').addEventListener('change',ev=>
  document.getElementById('id_product').value=ev.target.value )  
 <label for="id_product">Product</label>
<div class="card my-5">
  <div class="card-body">
    <div class="select-menu my-5">
      <select name="product" class="custom-select product-select" id="id_product">
        <option value="" selected="">---------</option>
        <option value="3">ABC test product 2</option>
        <option value="2">DEF test product 1</option>
        <option value="1">GHI test product 0</option>
      </select>
    </div>
  </div>
</div>
<div class="card my-5">
  <div class="card-body">
    <label>custom<br>
    <select id="id_custom">
      <option value="">---------</option>
      <option value="3">ABC test product 2</option>
      <option value="2">DEF test product 1</option>
      <option value="1">GHI test product 0</option>
    </select></label>
  </div>
</div>  

Если вы хотите, чтобы изменение было синхронизировано в обоих направлениях, вы могли бы сделать это:

 document.getElementById('filt').oninput=ev=>
  [...document.getElementById('id_custom').children].forEach(o=>
     o.classList.toggle('hidden',o.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase())<0)
  )
document.getElementById('container').addEventListener('change',ev=>
  ev.target.tagName=='SELECT' amp;amp; [...document.querySelectorAll('SELECT')].forEach(s=>s.value=ev.target.value)
)  
 .hidden {display:none}  
 <div id="container">
<label for="id_product">Product</label>
<div class="card my-5">
  <div class="card-body">
    <div class="select-menu my-5">
      <select name="product" class="custom-select product-select" id="id_product">
        <option value="" selected="">---------</option>
        <option value="3">ABC test product 2</option>
        <option value="2">DEF test product 1</option>
        <option value="1">GHI test product 0</option>
      </select>
    </div>
  </div>
</div>
<div class="card my-5">
  <div class="card-body">
    <label>custom<br>
    <input type="text" id="filt" placeholder="filter ..."><br>
    <select id="id_custom">
      <option value="">---------</option>
      <option value="3">ABC test product 2</option>
      <option value="2">DEF test product 1</option>
      <option value="1">GHI test product 0</option>
    </select></label>
  </div>
</div>
</div>  

В этом фрагменте я также включил простой механизм фильтрации для второго поля выбора. Дополнительная библиотека или фреймворк не требуются.

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

1. Да, сэр. Но причина в том, что я не использую какой-либо фреймворк интерфейса, такой как react, если у меня есть 1000 вариантов, то выбрать конкретный будет сложно. Думаю, небольшая настройка и добавление фильтра поиска сверху очень помогают.

2. Хорошо, я это вижу, но вы можете сделать то же самое и со стандартным элементом select … 😉

3. Действительно? Не могли бы вы рассказать мне, как или предложить мне какую-либо ссылку или документы для просмотра.

4. Смотрите мой измененный ответ (второй, скрытый фрагмент, нижняя часть)!

5. Спасибо за ответ. Извините, я не смотрел на это раньше.