我正在使用select2
自定义数据适配器。提供给select2
的所有数据都是在网页中本地生成的(因此不需要使用ajax)。由于query
方法可以生成很多结果(约5k),打开选择框的速度相当慢。
作为补救措施,我想使用无限滚动。自定义数据适配器的Documentation表示query
方法应与page
一起收到term
参数:
@param params.page应加载的特定页面。这是 通常在使用依赖的远程数据集时提供 在分页上确定应该显示哪些对象。
但事实并非如此:仅存在term
。我试图返回more: true
或more: 1000
,但这没有帮助。我想这是因为,默认情况下,infinite scroll is enabled iff ajax is enabled。
我猜测启用无限滚动将涉及使用amd.require
,但我不确定该怎么做。我试过这段代码:
$.fn.select2.amd.require(
["select2/utils", "select2/dropdown/infiniteScroll"],
(Utils, InfiniteScroll) =>
input.data("select2").options.options.resultsAdapter =
Utils.Decorate(input.data("select2").options.options.resultsAdapter, InfiniteScroll)
)
这是咖啡脚本,但我希望每个人都能阅读。 input
是包含选择框的DOM
元素 - 我之前做过input.select2( //options )
我的问题基本上是,如何在没有ajax
的情况下启用无限滚动?
答案 0 :(得分:11)
Select2
, ajax
将仅启用无限滚动。幸运的是,我们可以启用它并仍然使用我们自己的适配器。因此,将空对象放入ajax
选项就可以了。
$("select").select2({
ajax: {},
dataAdapter: CustomData
});
接下来,定义您自己的数据适配器。在其中,商店query
将pagination
信息推送到回调中。
CustomData.prototype.query = function (params, callback) {
if (!("page" in params)) {
params.page = 1;
}
var data = {};
# you probably want to do some filtering, basing on params.term
data.results = items.slice((params.page - 1) * pageSize, params.page * pageSize);
data.pagination = {};
data.pagination.more = params.page * pageSize < items.length;
callback(data);
};
答案 1 :(得分:9)
展开this answer以展示如何保留select2附带的搜索功能。谢谢Paperback Writer!
还引用this example如何使用客户端数据源实现无限滚动,使用select2版本3.4.5。
此示例使用select标记中的oringal选项来构建列表,而不是在我的情况下调用的item数组。
function contains(str1, str2) {
return new RegExp(str2, "i").test(str1);
}
CustomData.prototype.query = function (params, callback) {
if (!("page" in params)) {
params.page = 1;
}
var pageSize = 50;
var results = this.$element.children().map(function(i, elem) {
if (contains(elem.innerText, params.term)) {
return {
id:[elem.innerText, i].join(""),
text:elem.innerText
};
}
});
callback({
results:results.slice((params.page - 1) * pageSize, params.page * pageSize),
pagination:{
more:results.length >= params.page * pageSize
}
});
};
这是jsfiddle
答案 2 :(得分:9)
我觉得上面的答案需要更好的示范。选择2 4.0.0 introduces可以自定义adapters。使用ajax: {}
技巧,我创建了一个直接使用本地JSON的自定义dataAdapter jsonAdapter
。另请注意,使用大型JSON字符串,Select2的4.0.0版本具有令人印象深刻的性能。我使用了online JSON generator并创建了10,000个名称作为测试数据。但是,这个例子非常混乱。虽然这有效,但我希望有更好的方法。
请在此处查看完整的小提琴:http://jsfiddle.net/a8La61rL/
$.fn.select2.amd.define('select2/data/customAdapter', ['select2/data/array', 'select2/utils'],
function (ArrayData, Utils) {
function CustomDataAdapter($element, options) {
CustomDataAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(CustomDataAdapter, ArrayData);
CustomDataAdapter.prototype.current = function (callback) {
var found = [],
findValue = null,
initialValue = this.options.options.initialValue,
selectedValue = this.$element.val(),
jsonData = this.options.options.jsonData,
jsonMap = this.options.options.jsonMap;
if (initialValue !== null){
findValue = initialValue;
this.options.options.initialValue = null; // <-- set null after initialized
}
else if (selectedValue !== null){
findValue = selectedValue;
}
if(!this.$element.prop('multiple')){
findValue = [findValue];
this.$element.html(); // <-- if I do this for multiple then it breaks
}
// Query value(s)
for (var v = 0; v < findValue.length; v++) {
for (var i = 0, len = jsonData.length; i < len; i++) {
if (findValue[v] == jsonData[i][jsonMap.id]){
found.push({id: jsonData[i][jsonMap.id], text: jsonData[i][jsonMap.text]});
if(this.$element.find("option[value='" + findValue[v] + "']").length == 0) {
this.$element.append(new Option(jsonData[i][jsonMap.text], jsonData[i][jsonMap.id]));
}
break;
}
}
}
// Set found matches as selected
this.$element.find("option").prop("selected", false).removeAttr("selected");
for (var v = 0; v < found.length; v++) {
this.$element.find("option[value='" + found[v].id + "']").prop("selected", true).attr("selected","selected");
}
// If nothing was found, then set to top option (for single select)
if (!found.length && !this.$element.prop('multiple')) { // default to top option
found.push({id: jsonData[0][jsonMap.id], text: jsonData[0][jsonMap.text]});
this.$element.html(new Option(jsonData[0][jsonMap.text], jsonData[0][jsonMap.id], true, true));
}
callback(found);
};
CustomDataAdapter.prototype.query = function (params, callback) {
if (!("page" in params)) {
params.page = 1;
}
var jsonData = this.options.options.jsonData,
pageSize = this.options.options.pageSize,
jsonMap = this.options.options.jsonMap;
var results = $.map(jsonData, function(obj) {
// Search
if(new RegExp(params.term, "i").test(obj[jsonMap.text])) {
return {
id:obj[jsonMap.id],
text:obj[jsonMap.text]
};
}
});
callback({
results:results.slice((params.page - 1) * pageSize, params.page * pageSize),
pagination:{
more:results.length >= params.page * pageSize
}
});
};
return CustomDataAdapter;
});
var jsonAdapter=$.fn.select2.amd.require('select2/data/customAdapter');
答案 3 :(得分:2)
我发现劫持ajax适配器要比上面的答案创建一个全新的CustomAdapter容易得多。上面的答案实际上似乎并不支持分页,因为它们都是从不支持分页的数组开始的。它还不支持延迟处理。
window.myarray = Array(10000).fill(0).map((x,i)=>'Index' + i);
let timer = null;
$('select[name=test]')
.empty()
.select2({
ajax: {
delay: 250,
transport: function(params, success, failure) {
let pageSize = 10;
let term = (params.data.term || '').toLowerCase();
let page = (params.data.page || 1);
if (timer)
clearTimeout(timer);
timer = setTimeout(function(){
timer = null;
let results = window.myarray // your base array here
.filter(function(f){
// your custom filtering here.
return f.toLowerCase().includes(term);
})
.map(function(f){
// your custom mapping here.
return { id: f, text: f};
});
let paged = results.slice((page -1) * pageSize, page * pageSize);
let options = {
results: paged,
pagination: {
more: results.length >= page * pageSize
}
};
success(options);
}, params.delay);
}
},
tags: true
});
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/js/select2.full.min.js"></script>
<select name='test' data-width="500px"><option>test</option></select>
答案 4 :(得分:0)
这不是一个直接的答案:经过一段时间的努力,我最终转向选择。选择2对非Ajax搜索的支持,因为版本4,非常复杂,接近荒谬,并没有很好地记录。 Selectize明确支持非Ajax搜索:您只需实现一个返回列表的函数。
答案 5 :(得分:0)
这是具有分页功能的Select2 v4的较短的可搜索版本。它使用lo-dash作为 搜索。
http://jsfiddle.net/favm4dp9/2/
$(function () {
items = []
for (var i = 0; i < 1000; i++) {
items.push({ id: i, text : "item " + i})
}
pageSize = 50
$.fn.select2.amd.require(["select2/data/array", "select2/utils"],
function (ArrayData, Utils) {
function CustomData($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
}
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
var results = [];
if (params.term && params.term !== '') {
results = _.filter(items, function(e) {
return e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0;
});
} else {
results = items;
}
if (!("page" in params)) {
params.page = 1;
}
var data = {};
data.results = results.slice((params.page - 1) * pageSize, params.page * pageSize);
data.pagination = {};
data.pagination.more = params.page * pageSize < results.length;
callback(data);
};
$(document).ready(function () {
$("select").select2({
ajax: {},
dataAdapter: CustomData
});
});
})
});
搜索循环最初来自这些旧的Select4 v3函数:https://stackoverflow.com/a/25466453/5601169
答案 6 :(得分:0)
这些都不适合我。我不知道最初的问题是什么意思,但是在我的情况下,我正在使用角度和HTTP调用和服务,并希望避免AJAX调用。
因此,我只想代替AJAX调用服务方法。这甚至没有在图书馆的网站上记录,但是我以某种方式找到了使用<content>
149326
如果像我这样的人来这儿,那就去!
答案 7 :(得分:0)
我对角度9的解决方案
this.$select2 = this.$element.select2({
width: '100%',
language: "tr",
ajax: {
transport: (params, success, failure) => {
let pageSize = 10;
let page = (params.data.page || 1);
let results = this.options
.filter(i => new RegExp(params.data.term, "i").test(i.text))
.map(i => {
return {
id: i.value,
text: i.text
}
});
let paged = results.slice((page - 1) * pageSize, page * pageSize);
let options = {
results: paged,
pagination: {
more: results.length >= page * pageSize
}
};
success(options);
}
}
});
}