Выбор optgroup с помощью select2
я использовал select2 для выбора нескольких параметров из раскрывающегося списка, но возможно ли select2 выбрать полную группу optgroup?? Я хочу, чтобы при выборе пользователем группы опций были выбраны все дочерние параметры. И я хочу сделать это с помощью jQuery Select2
. Как я мог это сделать?
6 ответов
это возможно, если вы вернете Select2 со скрытым элементом ввода -- вместо элемента select.
чтобы сделать параметр группы выбираемым, вы должны дать ему "id", но, похоже, это может быть пустая строка. Затем вы можете использовать событие "select2-selecting", чтобы предотвратить выбор опции группы и вместо этого выбрать дочерние параметры.
кроме того, a query
функция может быть предоставлена, чтобы предотвратить появление опции группы в списке после того, как все его дочерние параметры были выбраны.
если у вас есть варианты, как этот:
var FRUIT_GROUPS = [
{
id: '',
text: 'Citrus',
children: [
{ id: 'c1', text: 'Grapefruit' },
{ id: 'c2', text: 'Orange' },
{ id: 'c3', text: 'Lemon' },
{ id: 'c4', text: 'Lime' }
]
},
{
id: '',
text: 'Other',
children: [
{ id: 'o1', text: 'Apple' },
{ id: 'o2', text: 'Mango' },
{ id: 'o3', text: 'Banana' }
]
}
];
можно инструментовать Select2 такой:
$('#fruitSelect').select2({
multiple: true,
placeholder: "Select fruits...",
data: FRUIT_GROUPS,
query: function(options) {
var selectedIds = options.element.select2('val');
var selectableGroups = $.map(this.data, function(group) {
var areChildrenAllSelected = true;
$.each(group.children, function(i, child) {
if (selectedIds.indexOf(child.id) < 0) {
areChildrenAllSelected = false;
return false; // Short-circuit $.each()
}
});
return !areChildrenAllSelected ? group : null;
});
options.callback({ results: selectableGroups });
}
}).on('select2-selecting', function(e) {
var $select = $(this);
if (e.val == '') { // Assume only groups have an empty id
e.preventDefault();
$select.select2('data', $select.select2('data').concat(e.choice.children));
$select.select2('close');
}
});
здесь jsfiddle без query
функция, где параметры группы по-прежнему отображаются, когда выбраны все их дочерние параметры.
я использовал код Джона, но моя проблема заключалась в том, что мне нужна была возможность фильтрации, поэтому я добавил его. Вы можете увидеть код, работающий на jsfiddle.
Это код запроса:
query: function (options) {
var selectedIds = options.element.select2('val');
var data = jQuery.extend(true, {}, FRUIT_GROUPS);
var selectableGroups = $.map(data, function (group) {
var areAllChildrenSelected = true,
parentMatchTerm = false,
anyChildMatchTerm = false;
if (group.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0) {
parentMatchTerm = true;
}
var i = group.children.length
while (i--) {
var child = group.children[i];
if (selectedIds.indexOf(child.id) < 0) {
areAllChildrenSelected = false;
};
if (options.term == '' || (child.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0)) {
anyChildMatchTerm = true;
}
else if (!parentMatchTerm) {
var index = group.children.indexOf(child);
if (index > -1) {
group.children.splice(index, 1);
};
};
};
return (!areAllChildrenSelected && (parentMatchTerm || anyChildMatchTerm)) ? group : null;
});
options.callback({ results: selectableGroups });
}
сначала дайте ID для вашего выбора например
<select style="width: 95%" id="selectgroup">
а затем добавьте класс в свою optgroup как
<optgroup value="ATZ" label="Alaskan/Hawaiian Time Zone" class="select2-result-selectable">
а затем добавьте это
$('#selectgroup').select2({
}).on('select2-selecting', function (e) {
debugger;
var $select = $(this);
if (e.val == undefined) {
e.preventDefault();
var childIds = $.map(e.choice.children, function (child) {
return child.id;
});
$select.select2('val', $select.select2('val').concat(childIds));
$select.select2('close');
}
});
Если вы нажмете на optgroup, он выберет все параметры под optgroup.
в Select2 v4 я обнаружил, что ответ Джона S не будет работать (посмотреть здесь). Я загружаю свои данные в виде массива с помощью AJAX и создал обходной путь:
$(document).on("click", ".select2-results__group", function(){
var input = $(this);
var location = input.html();
// Find the items with this location
var options = $('#select2 option');
$.each(options, function(key, value){
var name = $(value).html();
// The option contains the location, so mark it as selected
if(name.indexOf(location) >= 0){
$(value).prop("selected","selected");
}
});
$("#select2").trigger("change");
});
Я группирую свои элементы по местоположению, и каждый параметр содержит имя местоположения где-то в html. Каждый раз, когда нажимается заголовок optgroup, я получаю его местоположение (имя, отображаемое в раскрывающемся списке). Затем я просматриваю все параметры в таблице #select2 и нахожу, какие из них содержат это местоположение в формат html.
Я знаю, что это хаки обходной путь, но, надеюсь, это помогает/указывает в правильном направлении.
John S, при условии, что пример работает очень хорошо (для V3) для большинства случаев. Однако у него есть одна ошибка:
предполагая, что список выбора достаточно длинный, чтобы иметь прокрутку. При выборе любого элемента в любой группе, который доступен только после прокрутки вниз-вы больше не можете выбрать следующий элемент после выбранного из этой группы. Это потому, что ensureHighlightVisible метод select2 начинает плохо себя вести, потому что селекторы, которые он использует, сделаны с использованием предположений, что группа всегда "невыбираемый". Таким образом, прокрутка будет прыгать каждый раз, когда вы пытаетесь выбрать элемент.
к сожалению, хотя это решение выглядит очень хорошо - я отбросил его и повторно реализовал его без использования идентификаторов группы:
$selectEl..on("select2-open", function(event) {
$(event.target).data("select2").dropdown.on("click", "li.select2-result-unselectable", selectGroup);
$(event.target).data("select2").dropdown.on("mousemove-filtered", "li.select2-result-unselectable", highlight);
}).on("select2-close", function(event) {
$(event.target).data("select2").dropdown.off("click", "li.select2-result-unselectable", selectGroup);
$(event.target).data("select2").dropdown.off("mousemove-filtered", "li.select2-result-unselectable", highlight);
});
и
// selection of the group.
function selectGroup(e) {
var $li = $(this);
e.preventDefault();
$select.select2('data', $select.select2('data').concat($li.data("select2Data").children));
$select.select2('close');
_this.$field.trigger('change');
}
// highlight of the group.
function highlight(e) {
if ($(e.target).hasClass("select2-result-unselectable") || $(e.target.parentNode).hasClass('select2-result-unselectable')) {
e.preventDefault();
e.stopPropagation();
$select.data("select2").dropdown.find(".select2-highlighted").removeClass("select2-highlighted");
$(this).addClass("select2-highlighted");
}
}
Ну, я столкнулся с этой проблемой, и я обнаружил, что каждый раз, когда select2 (Select2 4.0.5) открывается, он добавляет элемент span перед закрывающим элементом body. Кроме того, внутри элемента span добавляется ul с идентификатором: select2-X-results, где X-идентификатор select2. Поэтому я нашел следующий обходной путь (jsfiddle):
var countries = [{
"id": 1,
"text": "Greece",
"children": [{
"id": "Athens",
"text": "Athens"
}, {
"id": "Thessalonica",
"text": "Thessalonica"
}]
}, {
"id": 2,
"text": "Italy",
"children": [{
"id": "Milan",
"text": "Milan"
}, {
"id": "Rome",
"text": "Rome"
}]
}];
$('#selectcountry').select2({
placeholder: "Please select cities",
allowClear: true,
width: '100%',
data: countries
});
$('#selectcountry').on('select2:open', function(e) {
$('#select2-selectcountry-results').on('click', function(event) {
event.stopPropagation();
var data = $(event.target).html();
var selectedOptionGroup = data.toString().trim();
var groupchildren = [];
for (var i = 0; i < countries.length; i++) {
if (selectedOptionGroup.toString() === countries[i].text.toString()) {
for (var j = 0; j < countries[i].children.length; j++) {
groupchildren.push(countries[i].children[j].id);
}
}
}
var options = [];
options = $('#selectcountry').val();
if (options === null || options === '') {
options = [];
}
for (var i = 0; i < groupchildren.length; i++) {
var count = 0;
for (var j = 0; j < options.length; j++) {
if (options[j].toString() === groupchildren[i].toString()) {
count++;
break;
}
}
if (count === 0) {
options.push(groupchildren[i].toString());
}
}
$('#selectcountry').val(options);
$('#selectcountry').trigger('change'); // Notify any JS components that the value changed
$('#selectcountry').select2('close');
});
});
li.select2-results__option strong.select2-results__group:hover {
background-color: #ddd;
cursor: pointer;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.full.min.js"></script>
<h1>Selectable optgroup using select2</h1>
<select id="selectcountry" name="country[]" class="form-control" multiple style="width: 100%"></select>