web-dev-qa-db-ja.com

ajaxなしでselect24.0で無限スクロールを有効にする方法

カスタムデータアダプタで_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なしで無限スクロールを有効にするにはどうすればよいですか?

10

Select2は、ajaxが有効になっている場合にのみ、無限スクロールを有効にします。幸い、それを有効にしても、独自のアダプターを使用できます。したがって、空のオブジェクトをajaxオプションに入れるとうまくいきます。

$("select").select2({
  ajax: {},
  dataAdapter: CustomData
});

次に、独自のデータアダプタを定義します。その中で、inn querypagination情報をコールバックにプッシュします。

    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);
    };

これが フルフィドル

14

上記の答えにはもっと良いデモンストレーションが必要だと感じました。 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');
10
prograhammer

この回答 を展開して、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

10
mothmonsterman

上記の回答のようにまったく新しい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>
2
Robert McKee

これは、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

1
lofihelsinki

これは直接的な答えではありません。しばらくの間これに苦労した後、私は選択するように切り替えることになりました。 Select2の非Ajax検索のサポートは、バージョン4以降、非常に複雑で、ばかげていることに隣接しており、十分に文書化されていません。 Selectizeは、Ajax以外の検索を明示的にサポートしています。つまり、リストを返す関数を実装するだけです。

0
Max