カスタムデータアダプタで_select2
_を使用しています。 _select2
_に提供されるすべてのデータは、Webページでローカルに生成されます(したがって、ajaxを使用する必要はありません)。 query
メソッドは多くの結果(約5k)を生成する可能性があるため、選択ボックスを開くのは非常に時間がかかります。
救済策として、無限スクロールを使いたかったのです。 ドキュメント カスタムデータアダプタの場合、query
メソッドはpage
と一緒にterm
パラメータを受け取る必要があると述べています。
@ paramparams.pageロードする必要のある特定のページ。これは通常、表示するオブジェクトを決定するためにページネーションに依存するリモートデータセットを操作するときに提供されます。
ただし、そうではありません。term
のみが存在します。 _more: true
_または_more: 1000
_を返そうとしましたが、役に立ちませんでした。これは、デフォルトで ajaxが有効になっている場合は無限スクロールが有効になっている であるためだと思います。
無限スクロールを有効にするには、_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
なしで無限スクロールを有効にするにはどうすればよいですか?
Select2
は、ajax
が有効になっている場合にのみ、無限スクロールを有効にします。幸い、それを有効にしても、独自のアダプターを使用できます。したがって、空のオブジェクトをajax
オプションに入れるとうまくいきます。
$("select").select2({
ajax: {},
dataAdapter: CustomData
});
次に、独自のデータアダプタを定義します。その中で、inn 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);
};
これが フルフィドル
上記の答えにはもっと良いデモンストレーションが必要だと感じました。 Select2 4.0.0 導入 カスタムを実行する機能 アダプタ 。 ajax: {}
トリックを使用して、ローカルJSONを直接使用するカスタムdataAdapter jsonAdapter
を作成しました。また、Select2の4.0.0リリースが、大きなJSON文字列を使用して印象的なパフォーマンスを発揮していることにも注目してください。 オンラインJSONジェネレーター を使用し、テストデータとして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');
この回答 を展開して、select2に付属する検索機能を保持する方法を示します。ありがとう ペイパーバックライター !
Select2バージョン3.4.5で、クライアント側のデータソースを使用して無限スクロールを実現する方法についても参照 この例 。
この例では、私の状況で求められていたアイテム配列の代わりに、selectタグのoringalオプションを使用してリストを作成します。
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
上記の回答のようにまったく新しいCustomAdapterを作成するよりも、ajaxアダプターをハイジャックする方が簡単であることがわかりました。上記の回答はすべて、ページングをサポートしていない配列から始まるため、実際にはページングをサポートしていないようです。また、遅延処理もサポートしていません。
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>
これは、shorter、ページングのあるSelect2v4の検索可能なバージョンです。検索には lo-dash を使用します。
[〜#〜]編集[〜#〜]新しいフィドル: http://jsfiddle.net/nea053tw/
$(function () {
items = []
for (var i = 0; i < 1000; i++) {
items.Push({ id: i, text : "item " + i})
}
pageSize = 50
jQuery.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
これは直接的な答えではありません。しばらくの間これに苦労した後、私は選択するように切り替えることになりました。 Select2の非Ajax検索のサポートは、バージョン4以降、非常に複雑で、ばかげていることに隣接しており、十分に文書化されていません。 Selectizeは、Ajax以外の検索を明示的にサポートしています。つまり、リストを返す関数を実装するだけです。