0

I am using select 2 plugin for multiple selection. when i click in select 2 box, its very slow. it takes time to show the list of options or make input box available for typing. probably its because data is large.

here is the code

    <select multiple class="chosen-multi-select" name="related_cities[]">
      <?php if(!empty($all_locations)){
        foreach($all_locations as $l):
        ?>
      <option value="<?php echo $l->id;?>"  <?php if(in_array($l->id,$related_selected)){ echo "selected"; } ?> ><?php echo $l->location;?></option>
      <?php endforeach; } ?>
    </select>

here $l variable has more than 10000 result. How to resolve this issue.

imgrv
  • 99
  • 3
  • 17
  • Rendering 10000 options is not the best practice. You can refer to https://stackoverflow.com/questions/9656523/jquery-autocomplete-with-callback-ajax-json to use the ajax autocomplete – Johnny Mar 16 '21 at 06:48
  • Please refer to this [Ajax (remote data)](https://select2.org/data-sources/ajax) and this answer as well [How to use Select2 with JSON via Ajax request?](https://stackoverflow.com/questions/20926707/how-to-use-select2-with-json-via-ajax-request) – Bhautik Mar 16 '21 at 06:48
  • https://select2.org/data-sources/ajax can be an option for you – Johnny Mar 16 '21 at 06:48
  • @Johnny@Bhautik - I am able to fetch the results using ajax, but i am not able to understand, how to parse that in select 2 multi select box. – imgrv Mar 16 '21 at 07:21

1 Answers1

0

I have come across the same problem recently and managed to solve the solution by writing a custom adaptor.

Here is my solution for select2 v4x

$.fn.select2.amd.define(
    "select2/data/customArray",
    [
        'select2/data/array',
        'select2/utils'
    ],
    function(ArrayAdapter, Utils) {
        function CustomArrayAdapter ($element, options) {
            var data = options.get("data");
            var pageLength = options.get("pageLength");

            this._data = data ? Array.from(data) : this._items($element);
            this._pageLength = pageLength || 25;

            CustomArrayAdapter.__super__.constructor.call(this, $element, options);
        };

        Utils.Extend(CustomArrayAdapter, ArrayAdapter);

        CustomArrayAdapter.prototype.query = function (params, callback) {
            var pageLength = this._pageLength;
            var page = params.page || 1;
            var term = params.term;
            var pagedData = [];
            var data = this._data;

            if (!!term) {
                data = data.filter(function (elemData) {
                    return (elemData.text.toLowerCase().indexOf(term.toLowerCase()) > -1)
                });
            }

            pagedData = data.slice(
                (page - 1) * pageLength,
                page * pageLength
            );

            callback({
                results: pagedData,
                pagination: {
                    more: data.length >= (page * pageLength)
                }
            });
        };

        CustomArrayAdapter.prototype._items = function($element) {
            var data = [];
            var self = this;

            var $options = $element.children();

            $options.each(function () {
                if (
                    this.tagName.toLowerCase() !== 'option' &&
                    this.tagName.toLowerCase() !== 'optgroup'
                ) {
                    return;
                }

                var $option = $(this);
                var option = self.item($option);

                data.push(option);
            });

            return data;
        }

        return CustomArrayAdapter;
    }
);

Now this one handles the pagination and searching for simple use cases. However, the
pagination would not simply work because the results should be properly handled by select2.

If we are using ajax data the default adaptors handle that, in our case we need to handle that ourselves.

So you would initialize your select2 with the following options.

$('select[name="related_cities[]"]').select2({
    pageLength: 15,
    dataAdapter: $.fn.select2.amd.require('select2/data/customArray'),
    resultsAdapter: $.fn.select2.amd.require(
        [
            'select2/utils',
            'select2/results',
            'select2/dropdown/infiniteScroll'
        ],
        function(Utils, ResultsList, InfiniteScroll) {
            var CustomResultsList = ResultsList;

            CustomResultsList = Utils.Decorate(
                 CustomResultsList,
                 InfiniteScroll
            );

            // If you want additional support functionalities
            // you would decorate this with the corresponding decorators.
            // please refer to the advanced section of select2 documentation

            return CustomResultsList;
        }
    )
});
Mohamed Mufeed
  • 1,290
  • 6
  • 12