Javascript 无法在 Select2 下拉列表中选择项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26074414/
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
Unable to select item in Select2 drop down
提问by user70192
I am working on an app that uses Select2 (version 3.5.1). The HTML to setup this drop down / autocomplete field looks like this:
我正在开发一个使用 Select2(版本 3.5.1)的应用程序。设置此下拉/自动完成字段的 HTML 如下所示:
<input id="mySelect" class="form-control" type="hidden">
The form-controlclass in this snippet comes from Bootstrap. I am initializing this field from JavaScript using the following:
form-control此代码段中的类来自 Bootstrap。我正在使用以下内容从 JavaScript 初始化此字段:
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
When my select field loads, it successfully renders. Once I type at least the fifth character, it successfully pulls items from the server and lists them as options. However, if I try to select one of them, nothing happens. The drop-down popup stays open. Nothing gets put in the actual field. There are no errors in the JavaScript console. Its like I didn't click anything.
当我的选择字段加载时,它成功呈现。一旦我至少输入了第五个字符,它就会成功地从服务器中提取项目并将它们列为选项。但是,如果我尝试选择其中之一,则没有任何反应。下拉弹出窗口保持打开状态。什么都没有放在实际的领域。JavaScript 控制台中没有错误。就像我没有点击任何东西一样。
In addition, I noticed that nothing is highlighted when I put my mouse over an item or attempt to navigate the list of options with the arrow keys.
此外,我注意到当我将鼠标悬停在一个项目上或尝试使用箭头键导航选项列表时,没有任何突出显示。
What am I doing wrong?
我究竟做错了什么?
回答by u2041954
What is happening:
怎么了:
By default, resultsof the object you are returning in ajax.resultsshould be an array in this structure [{id:1,text:"a"},{id:2,text:"b"}, ...].
默认情况下,results您返回的对象ajax.results应该是这个结构中的一个数组[{id:1,text:"a"},{id:2,text:"b"}, ...]。
results: function (data, page) {
var array = data.results; //depends on your JSON
return { results: array };
}
In Select2.jsit actually states:
在Select2.js 中,它实际上指出:
* @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
* The expected format is an object containing the following keys:
* results array of objects that will be used as choices
* more (optional) boolean indicating whether there are more results available
* Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
Reading the source code, we can see that ajax.resultsis called on AJAX success:
阅读源代码,我们可以看到ajax.results在AJAX上调用成功:
success: function (data) {
// TODO - replace query.page with query so users have access to term, page, etc.
// added query as third paramter to keep backwards compatibility
var results = options.results(data, query.page, query);
query.callback(results);
}
So ajax.resultsis really just a function for you to format your data into the appropriate structure ( e.g. [{id:a,text:"a"},{id:b,text:"b"}, ...]) before the data is passed to query.callback:
Soajax.results真的只是一个函数,您可以[{id:a,text:"a"},{id:b,text:"b"}, ...]在将数据传递给之前将数据格式化为适当的结构(例如)query.callback:
callback: this.bind(function (data) {
// ignore a response if the select2 has been closed before it was received
if (!self.opened()) return;
self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
self.postprocessResults(data, false, false);
if (data.more===true) {
more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
} else {
more.remove();
}
self.positionDropdown();
self.resultsPage = page;
self.context = data.context;
this.opts.element.trigger({ type: "select2-loaded", items: data });
})});
And what query.callbackeventually does is to set the logic up properly so that everything works fine when you choose one of the items and trigger .selectChoice.
query.callback最终要做的是正确设置逻辑,以便在您选择其中一项和 trigger 时一切正常.selectChoice。
selectChoice: function (choice) {
var selected = this.container.find(".select2-search-choice-focus");
if (selected.length && choice && choice[0] == selected[0]) {
} else {
if (selected.length) {
this.opts.element.trigger("choice-deselected", selected);
}
selected.removeClass("select2-search-choice-focus");
if (choice && choice.length) {
this.close();
choice.addClass("select2-search-choice-focus");
this.opts.element.trigger("choice-selected", choice);
}
}
}
So if there is some misconfiguration (e.g. resultsis not in the correct structure) that causes the class .select2-search-choice-focusnot to be added to the DOM element before .selectChoiceis called, this is what happens:
因此,如果存在一些错误配置(例如results,结构不正确)导致类.select2-search-choice-focus在.selectChoice调用之前未添加到 DOM 元素,则会发生以下情况:
The drop-down popup stays open. Nothing gets put in the actual field. There are no errors in the JavaScript console. Its like I didn't click anything.
下拉弹出窗口保持打开状态。什么都没有放在实际的领域。JavaScript 控制台中没有错误。就像我没有点击任何东西一样。
Solutions
解决方案
There are many solutions to this. One of them is, of course, do some array keys manipulation in ajax.results.
对此有很多解决方案。当然,其中之一是在ajax.results.
results: function (data, page) {
//data = { results:[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}] };
var array = data.results;
var i = 0;
while(i < array.length){
array[i]["id"] = array[i]['ItemId'];
array[i]["text"] = array[i]['ItemText'];
delete array[i]["ItemId"];
delete array[i]["ItemText"];
i++;
}
return { results: array };
}
But you may ask: why must the id be "id" and the text be "text" in the array?
但是您可能会问:为什么数组中的 id 必须是“id”而文本必须是“text”?
[{id:1,text:"a"},{id:2,text:"b"}]
Can the array be in this structure instead?
数组可以在这个结构中吗?
[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}]
The answer is yes. You just need to overwrite the idand textfunctions with your own functions.
答案是肯定的。你只需要用你自己的函数覆盖id和text函数。
Here are the original functions for .selecte2in Select2.js:
这里是原来的功能.selecte2在Select2.js:
id: function (e) { return e == undefined ? null : e.id; },
text: function (e) {
if (e && this.data && this.data.text) {
if ($.isFunction(this.data.text)) {
return this.data.text(e);
} else {
return e[this.data.text];
}
} else {
return e.text;
}
},
To overwrite them, just add your own functions inside the object you are passing to .selecte2:
要覆盖它们,只需在传递给的对象中添加您自己的函数.selecte2:
$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText }
......
});
Updates
更新
What else is happening :
还有什么事情发生:
However, the text of the selected item does not appear in the field after the list closes.
但是,列表关闭后,所选项目的文本不会出现在字段中。
This means .selectChoicehas been successfully executed. Now the problem lies in .updateSelection. In the source code:
这意味着.selectChoice已成功执行。现在问题出在.updateSelection. 在源代码中:
updateSelection: function (data) {
var container=this.selection.find(".select2-chosen"), formatted, cssClass;
this.selection.data("select2-data", data);
container.empty();
if (data !== null) {
formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
}
if (formatted !== undefined) {
container.append(formatted);
}
cssClass=this.opts.formatSelectionCssClass(data, container);
if (cssClass !== undefined) {
container.addClass(cssClass);
}
this.selection.removeClass("select2-default");
if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
this.container.addClass("select2-allowclear");
}
}
From here we can see that, before the corresponding string of text is placed into the input, it would call formatSelection.
从这里我们可以看到,在将相应的文本字符串放入输入之前,它会调用formatSelection.
formatSelection: function (data, container, escapeMarkup) {
return data ? escapeMarkup(this.text(data)) : undefined;
},
Update: Solution
更新:解决方案
Previously I thought this.text(data)can be overwritten by having text: funcion(item){ ... }in the parameters, but sadly it doesn't work that way.
以前我认为this.text(data)可以通过text: funcion(item){ ... }在参数中进行覆盖,但遗憾的是它不能那样工作。
Therefore to render the text properly in the field, you should overwrite formatSelectionby doing
因此,要在字段中正确呈现文本,您应该formatSelection通过执行覆盖
$('#mySelect').select2({
id: function (item) { return item.ItemId },
formatSelection: function (item) { return item.ItemText }
//......
});
instead of trying to overwrite text(which should supposedly have the same effect but this way of overwriting is not yet supported/implemented in the library)
而不是尝试覆盖text(这应该具有相同的效果,但库中尚不支持/实现这种覆盖方式)
$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText } //this will not work.
//......
});
回答by itsmejodie
The issue you are facing is that select2wants all your results to have an idproperty. If they don't you need to initialise with an idfunction which returns the id from each result.
您面临的问题是select2希望您的所有结果都具有id属性。如果他们不需要,您需要使用id从每个结果返回 id的函数进行初始化。
It will not allow you to select a result unless you satisfy one of these. So in the case of your example :
除非您满足其中之一,否则它不会允许您选择结果。所以在你的例子中:
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
id: function(item) { return item.ItemId; }, /* <-- ADDED FUNCTION */
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
回答by Danillo Corvalan
You need to provide an ID that returns from your API like @itsmejodie said.
The other problem is that you have to provide select2formatResultand formatSelectionfunctions, once you have it loaded from Ajax but you can't put htmlon that. e.g.:
您需要提供一个从您的 API 返回的 ID,如@itsmejodie 所说。另一个问题是你必须提供select2formatResult和formatSelection函数,一旦你从 Ajax 加载它,但你不能穿上html它。例如:
function format (item) {
return item.name;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 2,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'jsonp',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data };
}
},
formatResult: format,
formatSelection: format
});
});
回答by Manic Depression
For version 4 of Select2 use
对于 Select2 的第 4 版使用
processResults: function (data) {
instead of
代替
results: function (data) {

