如何在没有ajax的select2 4.0中启用无限滚动

Pap*_*ter 9 javascript jquery jquery-select2 jquery-select2-4

我正在使用select2自定义数据适配器.提供的所有数据select2都是在网页中本地生成的(因此不需要使用ajax).由于query方法可以生成很多结果(约5k),打开选择框的速度相当慢.

作为一种补救措施,我想使用无限滚动.自定义数据适配器的文档说该query方法应该接收page参数term:

@param params.page应加载的特定页面.这通常在使用远程数据集时提供,远程数据集依靠分页来确定应显示哪些对象.

但事实并非如此:只term存在.我试图返回more: truemore: 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)
)
Run Code Online (Sandbox Code Playgroud)

这是咖啡脚本,但我希望它对每个人都是可读的.inputDOM包含选择框的元素 - 我之前做过input.select2( //options )

我的问题基本上是,如何启用无限滚动ajax

Pap*_*ter 12

Select2如果ajax启用,将仅启用无限滚动.幸运的是,我们可以启用它并仍然使用我们自己的适配器.因此,将空对象放入ajax选项就可以了.

$("select").select2({
  ajax: {},
  dataAdapter: CustomData
});
Run Code Online (Sandbox Code Playgroud)

接下来,定义您自己的数据适配器.在其中,客栈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);
    };
Run Code Online (Sandbox Code Playgroud)

这是一个完整的小提琴

  • 它在 fiddle 上不起作用,因为 github 资源消失了。这是 CDN 上的资源 http://jsfiddle.net/m07c1Ldv/1/ (2认同)

hap*_*rry 10

扩展此答案以展示如何保留select2附带的搜索功能.谢谢平装作家!

还引用了此示例,了解如何使用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
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

这是一个jsfiddle


pro*_*mer 10

我觉得上面的答案需要更好的示范.Select2 4.0.0 引入了自定义适配器的功能.使用这个ajax: {}技巧,我创建了一个jsonAdapter直接使用本地JSON 的自定义dataAdapter .另请注意,使用大型JSON字符串,Select2 4.0.0版本的性能令人印象深刻.我使用了在线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');
Run Code Online (Sandbox Code Playgroud)

  • 我希望我可以在这10,000次以上投票.我确信这是有充分理由的,但似乎v4过度设计了.这需要花费数小时才能弄明白,但幸好我偶然发现了你的答案.谢谢@prograhammer (4认同)

Rob*_*Kee 6

我发现劫持 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
    });
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)