Динамическое создание выпадающих связанных списков select

DOM + javascript порою позволяют создавать удивительные вещи. Одна из этих вещей, которой я хочу с вами поделиться — это динамически формируемые выпадающие списки.

Постановка задачи

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

Итак, наша задача отталкивается от работы с некоторой таблицей. При формировании массива данных из php удобно пользоваться библиотекой json. А в конечных движках для этих целей бывают реализованы собственные встроенные средства. Например, Drupal имеет функцию drupal_to_js($variable). Не стану вдаваться в подробности json и конкретных движков, будем считать, что нам удалось объявить прайс как двумерный ассоциативный массив в javasctipt. Выглядит это примерно так:

После этого нам понадобятся два списка select, в которых мы и будем отображать наши списки динамически. Вот HTML код этих списков.

Обратите внимание, что списки уже содержат по одному элементу option. Второй список изначально скрыт от пользователя установкой стиля контейнера display = none. Мы будем также прятать список моделей, если бренд не выбран.

Вернемся к данным прайса. В каждой строке у нас есть — наименование бренда (firm), модель устройства (device), совместимый с устройством картридж (cart) и цена заправки в рублях (p). Для первого списка нам нужно выбрать не повторяющиеся названия брендов, а для второго использовать название устройства или название картриджа. Чтобы за один проход выбрать из прайса не повторяющиеся названия брендов, лучше всего позаботиться при формировании массива, чтобы строки были отсортированы по firm. Тогда можно написать такую функцию инициализации первого списка:

Для создания новых элементов списка мы используем конструктор Option(text, value), где text — это отображаемая метка элемента списка, а value — её значение. Сортированный по firm массив позволяет нам последовательно выбрать значения бредов и добавить их в список.

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

Осталось лишь что то делать при выборе конкретной модели. Привяжем к событию onchange второго списка функцию для вывода цены заправки выбранной модели картриджа.

Я позволил себе небольшую оптимизацию для данной функции, передавая в неё как входной параметр ссылку на второй список. Давайте посмотрим как все выглядит вместе (без объявления прайса).

HTML часть:

javascript часть:

Ну и для демонстрации — примерчик вживую:

Выберите бренд:

Мало букафф? Читайте есчо !

Опыт работы с C# Xamarin

Июнь 28, 2022 г.

Что такое Xamarin - следует почитать отдельно. Вкратце, это платформа с идеологией .NET, позволяет писать код сразу для разных платформ - iOS, Android, Win. Меня интересовала возможность на знакомом языке (C#), написать что либо под Android. Я ...

Читать

Конфигурация для миграции статей (node:blog) из CSV файла

Март 2, 2024 г.

Это пример миграции данных из CSV файла в Drupal. Данная миграция является основной в том смысле, что она ссылается на дочернюю миграцию, в ходе которой будут созданы параграфы (entity_reference_revisions:paragraph) с HTML контентом. А далее мы ...

Читать

Генерируем UUID прямо в шаблоне

Ноябрь 6, 2025 г.

Понадобилось мне сгенерировать уникальный код, чтобы привязать уникальные стили к конкретному контейнеру. Функция random в twig чаще всего достаточна для этой цели. Но хотелось пойти немного дальше, и вытащить сервис генерации UUID. Это нам приводит ...

Читать

Набор номера на смартфоне при нажатии на номер телефона на сайте

Сентябрь 10, 2015 г.

Мне казалось, что это естественная фича сотовых, когда тыкаешь в какое то число на странице сайта в мобильном браузере - он пытается с ним что то делать, предлагая свои обычные варианты - послать СМС или позвонить. Оказалось, что это не совсем ...

Читать
 

Комментарии к «Динамическое создание выпадающих связанных списков select»

Понравилась статья? Есть вопросы? - пишите в комментариях.



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

Много комментариев в “Динамическое создание выпадающих связанных списков select”

  1. Андрей:

    Добрый вечер! Попробовал реализовать Ваш выпадающий список с картинкой, но почему-то не работает. Понимаю, что делаю что-то не так, но что? Всё уже перепробовал, но увы знаний не хватает(. Первый список работает, а вот второй не выпадает, и соответственно не изображается картинка к нему. Подскажите пожалуйста. Вот HTML часть:

    Выберите бренд:

    — бренд не выбран —

    Выберите модель картриджа:

    — модель не выбрана —

    Вот javascript часть:
    var priceData = [ { «firm»: «Brother», «s_id»: «1», «device»: «Brother HL-1030/1230/1240/1250/1270», «cart»: «TN6300/6600», «p»: «380», «url»: «pics1/7688.png» }, { «firm»: «Brother», «s_id»: «1», «device»: «Brother HL-1430/1440/1450/1470», «cart»: «TN6300/6600», «p»: «380», «url»: «pics1/7689.jpg» }, { «firm»: «Brother», «s_id»: «1», «device»: «Brother MFC-8350/8750/9650/9660/9750/9760», «cart»: «TN6300/6600», «p»: «380», «url»: «pics1/7689.jpg» }, { «firm»: «Brother», «s_id»: «1», «device»: «Brother MFC-9850/9860/9870/9880», «cart»: «TN6300/6600», «p»: «380», «url»: «pics1/7689.jpg» }, { «firm»: «Brother», «s_id»: «1», «device»: «Brother HL-5040», «cart»: «HL7600», «p»: «380», «url»: «pics1/7689.jpg» }, { «firm»: «Brother», «s_id»: «1», «device»: «Brother HL-2030,HL-2070», «cart»: «TN2075», «p»: «380», «url»: «pics1/7689.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON MultiPass-10, FAX-B100/110/155/540/550 «, «cart»: «BX3», «p»: «250», «url»: «pics1/7689.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJ-30/BJC-50/55/70/80/85/BN-700 «, «cart»: «BC10», «p»: «150», «url»: «pics1/7693.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJ-30/BJC-50/70/80 «, «cart»: «BCI11-BLK», «p»: «150», «url»: «pics1/7694.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJC-70/50/55/80/85 (o) «, «cart»: «BCI11-COL», «p»: «200», «url»: «pics1/7695.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJC-210/240 «, «cart»: «BC05,PG36,38,41», «p»: «300», «url»: «pics1/7696.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJC-2000/2100/4000/4100/4200/4550/5500/S100 «, «cart»: «BC20», «p»: «250», «url»: «pics1/7697.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJC-2000/2100/4000/4100/4200/4550/5500/S100/FAX B215C/B230C «, «cart»: «BC21E-COL», «p»: «200», «url»: «pics1/7698.jpg» }, { «firm»: «Canon», «s_id»: «1», «device»: «CANON BJC-2000/2100/4000/4100/4200/4550/5500/S100/Fax B215C «, «cart»: «BCI21-BLK», «p»: «150», «url»: «pics1/7699.jpg» }];

    function firm_init() {
    var firmSelObj = document.getElementById(‘firm’);
    var priceLen = priceData.length;
    var selLen = firmSelObj.options.length;
    var lastFirm = «»;
    for (var i=0; i 0; i—) modelSelObj.remove(i);
    //загрузим список моделей соответствующего бренда
    var priceLen = priceData.length;
    var selLen = modelSelObj.options.length;
    for (var i=0; i < priceLen; i++) {
    var t = priceData[i];
    if (currentFirm == t.firm)
    modelSelObj.options[selLen ++] = new Option(t.device + " (" + t.cart + ")", i);
    }
    modelContainer.style.display = "block";
    }
    }

    function onchangeModelSelect(th) {
    var t = priceData[th.value];
    if (t != "") {
    var content = 'Цена выбранной модели:’
    + t.p + ‘ руб.’;
    var obj = document.getElementById(‘output’);
    obj.innerHTML = content;
    }
    }

    //инициализация первого списка
    firm_init();