Как создать зависимые списки select2.js?
есть два селекта
<select id="category" class="form-control" name="category_id">
<option value="Уборка и помощь по хозяйству">Уборка и помощь по хозяйству</option>
<option value="Виртиуальный помощник">Виртиуальный помощник</option>
<option value="Компьютернная помощь">Компьютернная помощь</option>
</select>
и
<select id="sub_category" class="form-control" name="sub_category_id"></select>
вот так подключаю их к select2
$('#category').select2({ placeholder: "Выберите из списка",allowClear: true,language: "ru",});
$('#sub_category').select2({ placeholder: "Выберите из списка",allowClear: true, language: "ru"});
Пытаюсь найти как сделать зависимые списки при помощи плагина select2. Те надо при выборе категории получать по ajax данные под категорий и вставлять во второй список . Пытался гуглить нет информации. Интересует формат ответа, у куда вставлять данные.
Ответы (2 шт):
Автор решения: Алексей Шиманский
→ Ссылка
В доках написано: https://select2.org/data-sources/ajax, атрибут data. По ajax запросу возвращаются данные, которые можно записать их в данный атрибут
$('#mySelect2').select2({
ajax: {
url: 'https://api.github.com/orgs/select2/repos',
data: function (params) {
var query = {
search: params.term,
type: 'public'
}
// Query parameters will be ?search=[term]&type=public
return query;
}
}
});
Ещё пример
$("#profiles-thread").select2({
minimumInputLength: 2,
tags: [],
ajax: {
url: URL,
dataType: 'json',
type: "GET",
quietMillis: 50,
data: function (term) {
return {
term: term
};
},
results: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.completeName,
slug: item.slug,
id: item.id
}
})
};
}
}
});
Если лень самому делать, то можете воспользоваться готовым классом. Пример: https://codepen.io/ajaxray/full/oBPbQe/
/**
* A Javascript module to loadeding/refreshing options of a select2 list box using ajax based on selection of another select2 list box.
*
* @url : https://gist.github.com/ajaxray/187e7c9a00666a7ffff52a8a69b8bf31
* @auther : Anis Uddin Ahmad <[email protected]>
*
* Live demo - https://codepen.io/ajaxray/full/oBPbQe/
* w: http://ajaxray.com | t: @ajaxray
*/
var Select2Cascade = (function(window, $) {
function Select2Cascade(parent, child, url, select2Options) {
var afterActions = [];
var options = select2Options || {};
// Register functions to be called after cascading data loading done
this.then = function(callback) {
afterActions.push(callback);
return this;
};
parent.select2(select2Options).on("change", function(e) {
child.prop("disabled", true);
var _this = this;
$.getJSON(url.replace(':parentId:', $(this).val()), function(items) {
var newOptions = '<option value="">-- Select --</option>';
for (var id in items) {
newOptions += '<option value="' + id + '">' + items[id] + '</option>';
}
child.select2('destroy').html(newOptions).prop("disabled", false)
.select2(options);
afterActions.forEach(function(callback) {
callback(parent, child, items);
});
});
});
}
return Select2Cascade;
})(window, $);
$(document).ready(function() {
var select2Options = {
width: 'resolve'
};
// Loading raw JSON files of a secret gist - https://gist.github.com/ajaxray/32c5a57fafc3f6bc4c430153d66a55f5
var apiUrl = 'https://gist.githubusercontent.com/ajaxray/32c5a57fafc3f6bc4c430153d66a55f5/raw/260a653e6347fb6d2360e8ec376a2dc4888c1afa/:parentId:.json';
$('select').select2(select2Options);
var cascadLoading = new Select2Cascade($('#type'), $('#subtype'), apiUrl, select2Options);
cascadLoading.then(function(parent, child, items) {
// Dump response data
console.log(items);
});
});
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
/* Everything but the jumbotron gets side spacing for mobile first views */
.header,
.marketing,
.footer {
padding-right: 15px;
padding-left: 15px;
}
/* Custom page header */
.header {
padding-bottom: 20px;
border-bottom: 1px solid #e5e5e5;
}
/* Make the masthead heading the same height as the navigation */
.header h3 {
margin-top: 0;
margin-bottom: 0;
line-height: 40px;
}
/* Custom page footer */
.footer {
padding-top: 19px;
color: #777;
border-top: 1px solid #e5e5e5;
}
/* Customize container */
@media (min-width: 768px) {
.container {
max-width: 730px;
}
}
.container-narrow>hr {
margin: 30px 0;
}
/* Supporting marketing content */
.marketing {
margin: 40px 0;
}
.marketing p+h4 {
margin-top: 28px;
}
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-right: 0;
padding-left: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<div class="container">
<div class="row">
<div class="col-sm-12">
<form class="form-horizontal">
<div class="form-group">
<label for="type" class="col-sm-5 control-label">I'd like to ride</label>
<div class="col-sm-5">
<select name="type" id="type" class="form-control">
<option>--Select your ride--</option>
<option value="animals">Animal</option>
<option value="vehicles">Vehicle</option>
</select>
</div>
</div>
<div class="form-group">
<label for="subtype" class="col-sm-5 control-label">More specifically</label>
<div class="col-sm-5">
<select name="subtype" id="subtype" class="form-control">
<option>-- Select type first--</option>
</select>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- /container -->
Автор решения: Макс
→ Ссылка
Зависимые списки на JavaScript любой вложенности
// <!-- Добавляем контейнер для корневого списка -->
// <div id="rootSelectContainer"></div>
// Исходный массив данных
const select_data = [ /* Объявление массива данных */
{ id: 1, parent_id: 0, action_name: 'Выберите категорию', action_template: '' }, /* Элемент массива данных */
{ id: 2, parent_id: 0, action_name: 'Категория 1', action_template: '' }, /* Элемент массива данных */
{ id: 3, parent_id: 0, action_name: 'Категория 2', action_template: '' },
{ id: 4, parent_id: 0, action_name: 'Категория 3', action_template: '' },
{ id: 5, parent_id: 2, action_name: 'Категория 1-1', action_template: '' },
{ id: 6, parent_id: 2, action_name: 'Категория 1-2', action_template: '' },
{ id: 7, parent_id: 2, action_name: 'Категория 1-3', action_template: '' },
{ id: 8, parent_id: 3, action_name: 'Категория 2-1', action_template: '' },
{ id: 9, parent_id: 3, action_name: 'Категория 2-2', action_template: '' },
{ id: 10, parent_id: 3, action_name: 'Категория 2-3', action_template: '' },
{ id: 11, parent_id: 4, action_name: 'Категория 3-1', action_template: '' },
{ id: 12, parent_id: 4, action_name: 'Категория 3-2', action_template: '' },
{ id: 13, parent_id: 4, action_name: 'Категория 3-3', action_template: '' },
];
//########################################################//
// Функция для создания древовидной структуры
function createTree(arr, parentId) { /* Объявление функции createTree с параметрами arr и parentId */
let tree = []; /* Инициализация пустого массива tree */
for (let i = 0; i < arr.length; i++) { /* Цикл по элементам массива arr */
if (arr[i].parent_id === parentId) { /* Условие: если parent_id элемента равен parentId */
let children = createTree(arr, arr[i].id); /* Рекурсивный вызов функции createTree для поиска дочерних элементов */
if (children.length) { /* Если есть дочерние элементы */
arr[i].children = children; /* Установка свойства children для текущего элемента */
}
tree.push(arr[i]); /* Добавление текущего элемента в массив tree */
}
}
return tree; /* Возврат результата - массива древовидной структуры */
}
//########################################################//
// Функция для создания и заполнения select с атрибутами data
function renderSelectOptions(tree, parentNode) { /* Объявление функции renderSelectOptions с параметрами tree и parentNode */
const select = document.createElement('select'); /* Создание элемента <select> */
select.onchange = function() { /* Установка обработчика события onchange для элемента select */
const selectedOption = this.value; /* Получение значения выбранной опции */
// Удаляем все следующие select элементы
let nextSibling = this.nextSibling; /* Получение следующего соседа элемента select */
while (nextSibling) { /* Цикл: пока есть следующий сосед */
parentNode.removeChild(nextSibling); /* Удаление следующего соседа от родительского узла */
nextSibling = this.nextSibling; /* Получение следующего соседа после удаления */
}
const selectedNode = tree.find(node => node.id == selectedOption); /* Поиск выбранного узла в дереве */
if (selectedNode && selectedNode.children) { /* Если выбранный узел и имеет дочерние элементы */
renderSelectOptions(selectedNode.children, parentNode); /* Рекурсивный вызов функции renderSelectOptions для отображения дочерних элементов */
}
};
tree.forEach(node => { /* Цикл по элементам дерева */
const option = document.createElement('option'); /* Создание элемента <option> */
option.value = node.id; /* Установка значения для опции */
option.textContent = node.action_name; /* Установка текста для опции */
option.setAttribute('data-parent_id', node.parent_id); /* Установка пользовательского атрибута data-parent_id */
option.setAttribute('data-action_template', node.action_template); /* Установка пользовательского атрибута data-action_template */
select.appendChild(option); /* Добавление опции в элемент select */
});
parentNode.appendChild(document.createElement('br')); // Добавляем перевод строки /* Добавление перевода строки после элемента select */
parentNode.appendChild(select); /* Добавление элемента select в родительский узел */
// Рекурсивно создаем дочерние элементы select
if (tree.length > 0 && tree[0].children) { /* Условие: если длина дерева больше нуля и первый элемент дерева имеет дочерние элементы */
renderSelectOptions(tree[0].children, parentNode); /* Рекурсивный вызов функции renderSelectOptions для отображения дочерних элементов */
}
}
//########################################################//
// Находим корневой контейнер для списка
const rootSelectContainer = document.getElementById('rootSelectContainer'); /* Получение элемента с идентификатором rootSelectContainer */
// Отображаем корневой список с атрибутами data
renderSelectOptions(createTree(select_data, 0), rootSelectContainer); /* Вызов функции renderSelectOptions для отображения корневого списка */