Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Как отобразить множественный выбор select? (https://javascript.ru/forum/dom-window/80907-kak-otobrazit-mnozhestvennyjj-vybor-select.html)

Oscillococcinum 24.08.2020 17:08

Как отобразить множественный выбор select?
 
Здравствуйте.

Есть пункт "Оборудование 1,2,3,4...". В каждом пункте, есть свои подпункты с множественным выбором, которые появляются после выбора основного.
Требуется вывести в отображение полный список выбранных данных (основной пункт "Оборудование 1-4" + все выбранные к нему подпункты).
Реализовать вывод данных, например, после нажатия на кнопку "показать". Либо, как у меня, без кнопки. В данный момент выводится в зависимости от выбора Оборудование 1-4, а вот подпункт выводится только для первого основного Оборудование 1. Должно получится так: "Вы выбрали: Оборудование 1; 1.1 текст; 1.3 текст" Подскажите пожалуйста..

Html:

<!DOCTYPE html>

<html>
    <head>
       <meta charset="utf-8">
       <title>TEST</title>
      <link rel="stylesheet" href="css/bootstrap.min.css">
      <link rel="stylesheet" href="css/custom.css">

</head>
<body>
  <form name="myForm">
  <select id="Dest" class="Validate_Required " name="Dest" aria-required="true" onChange="Selected(this)">
     <p><option value="0" selected="selected">-</option>
     <option value="1">1 Оборудование</option>
     <option value="2">2 Оборудование</option>
     <option value="3">3 Оборудование</option>
     <option value="4">4 Оборудование</option>
  </select></p>
  </form>

  <form name="myForms">
  <select id='Label1' style='display: none;' size="3" multiple></p>
  	<option value="0">1.1 текст</option>
    <option value="1">1.2 текст</option>
    <option value="2">1.3 текст</option>
  </select>
  </div>
  <select id='Label2' style='display: none;' size="3" multiple>
    <option value="0">2.1 текст</option>
    <option value="1">2.2 текст</option>
    <option value="2">2.3 текст</option>
  </div>
  </select>
</div>
<select id='Label3' style='display: none;' size="3" multiple>
  <option value="0">3.1 текст</option>
  <option value="1">3.2 текст</option>
  <option value="2">3.3 текст</option>
</div>
</select>

<select id='Label4' style='display: none;' size="3" multiple>
  <option value="0">4.1 текст</option>
  <option value="1">4.2 текст</option>
  <option value="2">4.3 текст</option>
</div>
</select>
</form>
<div id="selection"></div>
    </div>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
        <script src="app2.js"></script>
  </body>
</html>


JS:

function Selected(a) {
	var label = a.value;
	if (label==1) {
		document.getElementById("Label1").style.display='block';
		document.getElementById("Label2").style.display='none';
		document.getElementById("Label3").style.display='none';
    document.getElementById("Label4").style.display='none';


	} else if (label==2) {
		document.getElementById("Label1").style.display='none';
		document.getElementById("Label2").style.display='block';
		document.getElementById("Label3").style.display='none';
    document.getElementById("Label4").style.display='none';


	} else if (label==3) {
		document.getElementById("Label1").style.display='none';
		document.getElementById("Label2").style.display='none';
		document.getElementById("Label3").style.display='block';
    document.getElementById("Label4").style.display='none';


	} else if (label==4) {
		document.getElementById("Label1").style.display='none';
		document.getElementById("Label2").style.display='none';
		document.getElementById("Label3").style.display='none';
    document.getElementById("Label4").style.display='block';


	} else {
		document.getElementById("Label1").style.display='none';
		document.getElementById("Label2").style.display='none';
		document.getElementById("Label3").style.display='none';
    document.getElementById("Label4").style.display='none';
	}

}

var mySelect = myForm.Dest;
var mySelects = myForms.Label1;
var mySelectss = myForms.Dest3;
var mySelectsss = myForms.Dest4;
var mySelectssss = myForms.Dest5;

function changeOption(){

    var selection = document.getElementById("selection");
    var selectedOption = mySelect.options[mySelect.selectedIndex];
    var selectedOptions = mySelects.options[mySelects.selectedIndex];
    selection.textContent = "Вы выбрали: " + selectedOption.text + ";" + " " + selectedOptions.text;
    console.log(selection.textContent)
}

mySelect.addEventListener("change", changeOption);

laimas 25.08.2020 11:55

Убрать ошибки в верстке - непонятные закрывающие теги p и div. Списки в одну форму, делегируя ей обработку изменения в списках.

<style>
.second {
    display: none;
}
</style>

<form id="myForm">
    <select id="Dest" class="Validate_Required " name="Dest" aria-required="true">
        <option value="" disabled="" selected="selected">-</option>
        <option value="1">Оборудование 1</option>
        <option value="2">Оборудование 2</option>
        <option value="3">Оборудование 3</option>
        <option value="4">Оборудование 4</option>
    </select>
  
    <select class="second" size="3" multiple>
        <option value="0">1.1 текст</option>
        <option value="1">1.2 текст</option>
        <option value="2">1.3 текст</option>
    </select>
  
    <select class="second" size="3" multiple>
        <option value="0">2.1 текст</option>
        <option value="1">2.2 текст</option>
        <option value="2">2.3 текст</option>
    </select>

    <select class="second" size="3" multiple>
        <option value="0">3.1 текст</option>
        <option value="1">3.2 текст</option>
        <option value="2">3.3 текст</option>
    </select>
 
    <select class="second" size="3" multiple>
        <option value="0">4.1 текст</option>
        <option value="1">4.2 текст</option>
        <option value="2">4.3 текст</option>
    </select>
</form>

<div id="selection"></div>

<script>
document.getElementById('myForm').addEventListener('change', function(e) {
    let elm = [...e.currentTarget.elements],
        prt = elm[0].selectedIndex, 
        set = 'Вы выбрали: ' + elm[0].options[prt].text;
    
    elm.slice(1).forEach(function(e, i) {
        e.style.display = i == prt - 1 ? 'block' : 'none'    
    });
    
    [...elm[prt].options].forEach(function(e) {
        if(e.selected) set += '; ' + e.text
    });
    
    document.getElementById('selection').textContent = set;
});
</script>

Oscillococcinum 25.08.2020 13:17

Большое спасибо!

laimas 25.08.2020 20:10

Oscillococcinum,
добавьте в строке 49 условие перед циклом

if(e.target == elm[0])

чтобы лишний раз не перебирать списки.

Oscillococcinum 26.08.2020 09:48

Понял. Еще бы расшифровать для чайников все строки JS:-?

laimas 26.08.2020 10:48

Все подробно не буду, а в общем это:

//установка обработчика изменения в форме, собственно делегирование ей обработку событий списков
document.getElementById('myForm').addEventListener('change', function(e) {
    let elm = [...e.currentTarget.elements], //массив элементов формы, а это только списки
        prt = elm[0].selectedIndex, //первый элемент этого массива, это список Dest, получаем индекс выбранной в нем опции 
        set = 'Вы выбрали: ' + elm[0].options[prt].text; //получаем текст выбранной опции списка Dest 
    
    //если источник события это список Dest, отобразим зависимый список из вторичных списков (second)
    //для этого обходим в цикле их, а это срез массива элементов начиная со второго   
    if(e.target == elm[0]) elm.slice(1).forEach(function(e, i) {
        //если индекс списка second равен индексу выбранной опции списка Dest минус единица,
        //то показываем список, иначе скрываем список  
        e.style.display = i == prt - 1 ? 'block' : 'none'    
    });
    //опции списка second, чей индекс в наборе элементов формы равен индексу выбранной опции списка Dest обходим в цикле 
    [...elm[prt].options].forEach(function(e) {
        //если опция выбрана, то добавляем ее текст к тексту выбранной опции списка Dest
        if(e.selected) set += '; ' + e.text
    });
     
    document.getElementById('selection').textContent = set; //отображаем выбор
});


В данном примере класс second не является селектором для выбора элементов поэтому видимостью списков можно управлять удалением/добавлением этого класса списку, то есть:

//вместо 
e.style.display = i == prt - 1 ? 'block' : 'none'
//поступать так
e.classList.toggle('second', i != prt-1)


Не известно для чего это, но ранее выбранные опции в списках second не сбрасываются при изменениях в списке Dest.

laimas 27.08.2020 16:50

Oscillococcinum, дополню тут на ответ в личку. Если еще не понятно почему .addEventListener null, то обратите внимание, что мой js-код расположен после формы, то есть на момент его выполнения форма доступна. Если вы подключаете скрипт в шапке страницы, то устанавливать обработчик нужно по событию загрузки документа, в его обработчике.

Еще нужно учитывать, что вот такое [...e.currentTarget.elements] поддерживают не все браузеры, могут быть проблемы. А применено это здесь ради методов .slice() и .forEach(). Последний можно заменить на цикл for, он позволяет обойти коллекцию, которыми являются e.currentTarget.elements и elm[prt].options. Для обхода первой коллекции счетчик итерации начинать с 1, и .slice() не потребуется.

laimas 14.10.2020 11:50

На вопрос в личку "как всё из этого же кода получать по итогу в БД не значения option value, а напрямую текст этого option".

А что вы такое держите в базе, можно даже сказать "странной базе", если она содержит только уникальные значения сущностей без их описания?

Oscillococcinum 14.10.2020 13:08

БД пустая. Новые записи создаются, но не "Оборудование 1", а просто "1", т.е. в колонку записывается значение value (<option value="1">Оборудование 1</option>). Соответственно и вместо "1.1 текст", заносится значение value "0" (<option value="0">1.1 текст</option>)
Как доработать js код, чтобы заносилось не value но и сам текст.

laimas 14.10.2020 15:32

Цитата:

Сообщение от Oscillococcinum
Новые записи создаются, но не "Оборудование 1", а просто "1"

Это не запись, это глупость. :)

Давайте так, я пишу отвлеченно, дабы не тратить время на просмотр и уяснение того, что у вас в коде, а вы просто почитайте и подумайте.

Но все-таки кое что можно сказать по вашему коду. То что в нем, называют связанными списками, и чтобы их получить, нужна всего одна форма, а зачастую и она не нужна, нужен только один и тот же обработчик выбора в списках для получения последующего списка. У вас две формы.

И так. Я купец, современный, с компьютером. Получил выгодное предложение - "Огурцы соленые, поволжские" по пять целковых за бочку. Решил прикупить и добавляю их в базу. Для этого у меня есть форма, в которой я могу выбрать из списка (с именем category) уже имеющиеся в базе моей товарные категории или добавить новую. Пока у меня в базе нет вообще никаких категорий, список пуст.

А огурцы, это овощи, и вполне возможно, что будут выгодные предложения и по другим овощам, помидорам и прочим. Значит добавим в базу сначала категорию, в которой будем хранить и огурцы, и помидоры, и ... Значит вводим в поле "Название" - "Овощи".

Далее описанное добавление в базу, это асинхронные запросы.

Отправляю форму и в базу запишется вот такая запись, в таблице категорий, в ее полях, которые ранее определены в ней при ее создании:

category_table
---------------------------------------------------------------------------------
category_id | parent_id | level | name           | image            | date_add
---------------------------------------------------------------------------------
1           | 0         | 1     | Овощи          |                  | 2020-10-05


Здесь,

category_id - это уникальный идентификатор добавленной категории "Овощи", который формируется автоматически в этом поле средствами SQL. Это поле типа SMALLINT имеющее первичный ключ и атрибуты UNSIGNED, и AUTO_INCREMENT. Первый атрибут позволяет хранить в этом поле 65535 уникальных записей, думаю больше различных товарных категорий у меня не будет. Атрибут AUTO_INCREMENT, это "указание" SQL увеличивать на 1 последнее уникальное значение в этом поле, применяя его к новой записи. Так как до этого у меня не было никаких категорий, записей в этой таблице в базе, то это будет первая запись, а значит ее идентификатор принял значение 1 (0 + 1). Отсюда следует, что уникального значения 0 в базе никогда не будет, а самому такое создавать, это создавать для себя же проблемы. Если эту запись удалить из базы, то все равно SQL никогда уже не будет помещать в базу значение 1, все, оно умерло.

parent_id - идентификатор родительской категории. Так как у меня не было категорий, это первая, при отправлении формы список category не передал никакого значения, значит в базу пишется категория самого верхнего уровня, не принадлежащая никакой категории, поэтому для нее значение этого поля будет равно 0. Делается это просто, приведением к INTEGER принятого значения списка "category", пустое значение и вернет 0.

level - это уровень вложенности категорий в дереве категорий, позволяющий упростить построение на страницах меню категорий для покупателей. Так как это категория верхнего уровня, то ее уровень равен 1. Здесь это только пример, что вообще нужно хранить в базе (что требуется для тех или иных данных), а как это формируется и т.п., это отдельный разговор.

name - название категории, без которого никто не разберется, что это такое.

image - изображение категории, которое будет отображаться на страницах. Поле не обязательное, чисто "философский" вопрос надо, не надо.

date_add - дата добавления в базу. Это значение получается функцией SQL при добавлении записи в базу - NOW(). Дату можно также и не иметь в базе, но такие поля помогают в администрировании базы, при сортировке и фильтрации выборки.

Если в базе бы хранились только "циферки" можно было бы понять что содержит база, отображая в списках, в которых ничего нет по сути? Ежику понятно, что нет.

После записи в базу сервер возвращает клиенту данные для списка "category", в которых для него будет уже одна опция со значением 1 и текстом "Овощи". То есть, это запрос к базе с условием WHERE parent_id = 0. Получаются категории только верхнего уровня.

Теперь можно поместить в базу категорию "Огурцы" как принадлежащую категории "Овощи". Поэтому в списке "category" выбираем опцию "Овощи", а в поле ввода указываем имя "Огурцы". После этого в таблице будут следующие записи:

category_table
---------------------------------------------------------------------------------
category_id | parent_id | level | name           | image            | date_add
---------------------------------------------------------------------------------
1           | 0         | 1     | Овощи          |                  | 2020-10-05
2           | 1         | 2     | Огурцы         |                  | 2020-10-05


Категория "Огурцы" получила идентификатор равный 2 (1 + 1), а в parent_id записалось значение списка "category", указывая на то, что эта категория принадлежит категории "Овощи" (родительская категория), и она будет иметь второй уровень вложения, level равно 2.

Тут надо заметить, что при выборе в списке "category" опции "Овощи" визуально никаких изменений не будет, кроме изменения в списке. Хотя при каждом изменении в этом списке на сервер отправляется запрос с параметрами category=N (где N значение выбранной в списке опции), по которому в базе по этому параметру будет производится запрос WHERE parent_id = category. До добавления в базу категории "Огурцы" запрос WHERE parent_id = 1 ничего не вернет, так как нет пока у нее дочерних категорий, поэтому и не будет других изменений на странице.

Теперь можно было бы начать и добавление товаров в категорию "Огурцы", но они бывают соленые, маринованные, свежие, ... А кто-то любит соление, кто-то ненавидит маринада, а огурцы не только "поволжане" могут предложить, но и другие, да и "буржуи забугорные" тоже не откажутся свои всучить. Все свалить в кучу, значит заставить морщиться покупателей не переносящих маринад, читая "маринованные" при поиске закуски. Значит, разобьем огурцы на категории: "Свежие", "Соленые", "Маринованные", добавляя последовательно эти категории в базу как принадлежащие категории "Огурцы".

Выбираем опять категорию "Овощи". Теперь запрос на сервер с параметром category=1 и запросом к базе WHERE parent_id = 1, вернет одну запись со значением 2 и текстом "Огурцы". На странице справа от списка "Овощи" и вторым по порядку в форме добавляем второй список с именем "category", в котором можно выбрать опцию "Огурцы". Выбираем ее, вводим "Свежие" и отправляем форму. Так как списки имеют одно и тоже имя, и список с опцией "Огурцы" второй элемент формы, то на сервере значение поля "category" будет равно последнему значению элемента формы, то есть 2. Значит в базу эта категория запишется под category_id равное 3 и parent_id равное 2, а уровень вложения 3. После добавления всех этих категорий в базе будут записи:

category_table
---------------------------------------------------------------------------------
category_id | parent_id | level | name           | image            | date_add
---------------------------------------------------------------------------------
1           | 0         | 1     | Овощи          |                  | 2020-10-05
2           | 1         | 2     | Огурцы         |                  | 2020-10-05
3           | 2         | 3     | Свежие         |                  | 2020-10-05
4           | 2         | 3     | Соленые        |                  | 2020-10-05
5           | 2         | 3     | Маринованные   |                  | 2020-10-05


Теперь можно добавлять в эти категории товары от поволжан, курян, буржуев, ..., свежие, соленые, моченые, ... Выбирается категория верхнего уровня "Овощи", при этом все списки правее этого списка очищаются. После запроса category = 1 и WHERE parent_id = 1, возвращаются данные о категориях ей принадлежащих. Строится список этих категорий, у нас это будут пока только "Огурцы". Выбираем в нем "Огурцы", делается запрос к серверу/базе, в ней выбираются категории принадлежащие категории "Огурцы", WHERE parent_id = 2. Будут возвращены данные для третьего списка:

[
    {"category_id": 3, "name": "Свежие"},
    {"category_id": 4, "name": "Соленые"},
    {"category_id": 5, "name": "Маринованные"}   
]


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

Ваш код должен управлять архитектурой данных, которую описывает база. Эту архитектуру определяете вы, а никак не какой-то текст созданный руками как .html страница. Архитектура ваших данных в базе и есть первоисточник, он определяет на странице и текст, и значения, и связи. Что у вас, и как всем таким вы собираетесь управлять базой, которая по сути ничего полезного не несет, я не представляю.


Часовой пояс GMT +3, время: 05:11.