jQuery 使用 select2 可选择 optgroup
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26964909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Selectable optgroup using select2
提问by Buvin Perera
I have used select2 to select multiple options from a drop down, but is it possible for select2 to select the full optgroup?? What I want is when user select the option group all the child options should be selected. And I want to do this using jQuery Select2
. How could I do this?
我已经使用 select2 从下拉列表中选择多个选项,但是 select2 可以选择完整的 optgroup 吗?我想要的是当用户选择选项组时,应该选择所有子选项。我想使用 jQuery 来做到这一点Select2
。我怎么能这样做?
回答by John S
This is possible if you back the Select2 with a hidden input element -- instead of a select element.
如果您使用隐藏的输入元素而不是选择元素支持 Select2,则这是可能的。
To make a group option selectable, you must give it an "id", but it appears it can be an empty string. You can then use the "select2-selecting" event to prevent the group option from getting selected, and instead have its child options get selected.
要使组选项可选,您必须给它一个“id”,但它似乎可以是一个空字符串。然后,您可以使用“select2-selecting”事件来防止选择组选项,而是选择其子选项。
Additionally, a query
function can be provided to prevent a group option from appearing in the list after all its child options have been selected.
此外,query
可以提供一个功能,以防止在选择了所有子选项后组选项出现在列表中。
If you have options defined like this:
如果您有这样定义的选项:
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' }
]
}
];
You can instrument your Select2 like this:
您可以像这样检测 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');
}
});
Here is a jsfiddlewithout the query
function, where the group options still appear when all of their child options are selected.
这是一个没有函数的jsfiddlequery
,其中仍然在选择所有子选项时仍会显示组选项。
回答by mgalindez
I've used John's code, but my problem was that I needed the ability to filter, so I added it. You can see the code working on jsfiddle.
我使用了 John 的代码,但我的问题是我需要过滤功能,所以我添加了它。您可以看到在jsfiddle 上工作的代码。
This is the query code:
这是查询代码:
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 });
}
回答by Maitri
First give id to your select for example
例如,首先为您的选择提供 id
<select style="width: 95%" id="selectgroup">
<select style="width: 95%" id="selectgroup">
and then add class to your optgroup like
然后将类添加到您的 optgroup 中,例如
<optgroup value="ATZ" label="Alaskan/Hawaiian Time Zone" class="select2-result-selectable">
and then add this
然后添加这个
$('#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');
}
});
If you click on optgroup then It will select all the options under the optgroup.
如果您单击 optgroup,它将选择 optgroup 下的所有选项。
回答by Magno Alberto
I found a plugin for Select2 v4 which adds the ability to click on the optgroup to select/unselect all of child options. It worked perfectly for me. bnjmnhndrsn/select2-optgroup-select
我找到了一个 Select2 v4 插件,它增加了点击 optgroup 来选择/取消选择所有子选项的能力。它非常适合我。 bnjmnhndrsn/select2-optgroup-select
Thanks Ben Henderson!
感谢本·亨德森!
回答by jgmackay
In Select2 v4, I found that John S's answer won't work (see here). I am loading my data as an array using AJAX and created a workaround:
在 Select2 v4 中,我发现 John 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");
});
I am grouping my items by location, and each option contains the location name somewhere in it's html. Any time an optgroup header is clicked, I get it's location (the name displayed in the dropdown). Then I look through all options in the #select2 table and find which ones contain that location in its html.
我按位置对我的项目进行分组,每个选项都在它的 html 中的某处包含位置名称。任何时候单击 optgroup 标头时,我都会得到它的位置(显示在下拉列表中的名称)。然后我查看 #select2 表中的所有选项,并找到哪些选项在其 html 中包含该位置。
I know this is a hacky workaround, but hopefully it helps/points in the right direction.
我知道这是一个 hacky 解决方法,但希望它有助于/指向正确的方向。
回答by Ilya Shaikovsky
John S, provided example works really well (for V3) for most of the cases. However it has one bug:
John S,提供的示例在大多数情况下都非常有效(对于 V3)。但是它有一个错误:
Assuming the selection list is long enough to have scroll. When you select any item in any group that is only available after you scroll down - you can't select the next item after the one you selected from this group anymore. It is because ensureHighlightVisible method of select2 starts misbehaving because the selectors it is using made using assumptions that group is always 'unselectable'. So the scroll will jump every time you try to select the item.
假设选择列表足够长可以滚动。当您选择任何组中的任何项目时,只有在向下滚动后才可用 - 您不能再选择从该组中选择的项目之后的下一个项目。这是因为 select2 的 ensureHighlightVisible 方法开始行为不端,因为它使用的选择器使用组总是“不可选择”的假设。因此,每次尝试选择项目时,滚动条都会跳动。
So unfortunately although this solution looks really good - I dropped it and re-implemented it without using group id's:
所以不幸的是,尽管这个解决方案看起来非常好 - 我放弃了它并在不使用组 ID 的情况下重新实现了它:
$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);
});
and
和
// 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");
}
}
回答by Daniel Lemur
One option for V 4.0.2 using a select element:
使用 select 元素的 V 4.0.2 的一种选择:
<select style="width:100%;" id="source" multiple="" tabindex="-1" aria-hidden="true">
<optgroup class="select2-result-selectable" label="Statuses" >
<option value="1">Received</option>
<option value="2">Pending Acceptance</option>
</optgroup>
<optgroup class="select2-result-selectable" label="Progress" >
<option value="6">In Progress</option>
<option value="7">Follow Up</option>
</optgroup>
</select>
JS + JQuery:
JS + JQuery:
$(document).ready(function() {
$('#source').select2();
$(document).on("click", ".select2-results__group", function(){
var groupName = $(this).html()
var options = $('#source option');
$.each(options, function(key, value){
if($(value)[0].parentElement.label.indexOf(groupName) >= 0){
$(value).prop("selected","selected");
}
});
$("#source").trigger("change");
$("#source").select2('close');
});
});
Fiddle: https://jsfiddle.net/un1oL8w0/4/
回答by Sofoklis
Well, I came across this issue and I found that every time the select2 (Select2 4.0.5) opens it adds a span element before the closing body element. In addition, inside the span element adds a ul with the id: select2-X-results, where X is the select2 id. So I found the following workaround (jsfiddle):
好吧,我遇到了这个问题,我发现每次 select2 (Select2 4.0.5) 打开它都会在关闭 body 元素之前添加一个 span 元素。另外,在span元素里面添加了一个id的ul:select2-X-results,其中X是select2的id。所以我找到了以下解决方法(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>