web-dev-qa-db-fra.com

Select2 performance pour un grand ensemble d'éléments

J'utilise le plugin select2 jquery avec le bootstrap de Twitter. Cela fonctionne très bien pour un plus petit nombre d'éléments. Mais lorsque la liste est énorme (plus de 1500 éléments), elle ralentit vraiment. C'est le plus lent dans IE.

La liste déroulante normale fonctionne très rapidement avec plus de 1500 éléments. Y at-il des solutions de contournement pour cette situation?

34
Manish

Vous pouvez faire ce travail bien même dans IE8 avec la pagination des suggestions,

Code:

// Function to shuffle the demo data
function shuffle(str) {
  return str
    .split('')
    .sort(function() {
      return 0.5 - Math.random();
  })
.join('');
}

// For demonstration purposes we first make
// a huge array of demo data (20 000 items)
// HEADS UP; for the _.map function i use underscore (actually lo-dash) here
function mockData() {
  return _.map(_.range(1, 20000), function(i) {
    return {
      id: i,
      text: shuffle('te ststr ing to shuffle') + ' ' + i,
    };
  });
}
(function() {
  // init select 2
  $('#test').select2({
    data: mockData(),
    placeholder: 'search',
    multiple: true,
    // query with pagination
    query: function(q) {
      var pageSize,
        results,
        that = this;
      pageSize = 20; // or whatever pagesize
      results = [];
      if (q.term && q.term !== '') {
        // HEADS UP; for the _.filter function i use underscore (actually lo-dash) here
        results = _.filter(that.data, function(e) {
          return e.text.toUpperCase().indexOf(q.term.toUpperCase()) >= 0;
        });
      } else if (q.term === '') {
        results = that.data;
      }
      q.callback({
        results: results.slice((q.page - 1) * pageSize, q.page * pageSize),
        more: results.length >= q.page * pageSize,
      });
    },
  });
})();

exemple de travail avec 20000 éléments ici: http://embed.plnkr.co/db8SXs/preview

plnkr embed ne supporte pas IE8 alors essayez-le sur IE8 avec ce lien à la place: http://run.plnkr.co/plunks/db8SXs/

39
MarcusAsplund

Je sais que c'est une vieille question, mais je voulais partager ce qui a fonctionné pour moi. Si vous devez pré-charger la grande liste (cela peut être plus facile, selon que vous commenciez à partir de zéro ou que vous vous basiez sur le code de quelqu'un d'autre), utilisez la minimumInputLength comme décrit ici dans la documentation. La vaste liste d'options ne s'affiche que lorsque l'utilisateur a saisi quelques caractères. Cela réduit considérablement l'impact sur les performances lors du rendu lorsque la liste déroulante Select2 est réellement sélectionnée. J'espère que cela pourra aider!

25
BammaHamma

N'oubliez donc pas que vous chargez> 1 500 éléments réels sur la page sous la forme de <option>s, ce qui peut également nuire aux performances de la page. En tant qu'utilisateur suggéré dans le commentaire, vous pouvez résoudre le problème de performances en appelant AJAX vers un service backend qui renverra vos valeurs. 

Sélectionnez 2 instructions Ajax

5
Kelz

C'est une très vieille question et réponse et même nous avons une version plus récente de select2. mais si quelqu'un essaie de chercher aussi dans optgroup. peut essayer cette solution.

http://jsfiddle.net/na1zLkz3/4/

    // Function to shuffle the demo data 
var shuffle = function (str) {
    return str.split('').sort(function () {
      return 0.5 - Math.random();
    }).join('');
  };

// For demonstration purposes we first make
// a huge array of demo data (20 000 items)
// HEADS UP; for the _.map function i use underscore (actually lo-dash) here
var mockData = function () {
    var array = _.map(_.range(1, 10), function (i) {
        return {
          id  : i,
          text: shuffle('te ststr ing to shuffle') + ' ' + i
        };
      });
    return array;
  };
  var mockData1 = function () {
    var array = _.map(_.range(10, 15), function (i) {
        return {
          id  : i,
          text: shuffle('te ststr ing to shuffle') + ' ' + i
        };
      });
    return array;
  };
  var mockData2 = function () {
    var array = _.map(_.range(15, 20), function (i) {
        return {
          id  : i,
          text: shuffle('te ststr ing to shuffle') + ' ' + i
        };
      });
    return array;
  };
  // create demo data
  var dummyData = mockData();
  var dummyData1 = mockData1();
  var dummyData2 = mockData2();
  dummyData.Push({
  text: 'canada',
  children: dummyData1
  });
  dummyData.Push({
  text: 'USA',
  children: dummyData2
  });

  // init select 2
  $('#ddlCar').select2({
    data             : dummyData,
    // init selected from elements value
    initSelection    : function (element, callback) {
      var initialData = [];
      $(element.val().split(",")).each(function () {
        initialData.Push({
          id  : this,
          text: this
        });
      });
      callback(initialData);
    },

    // NOT NEEDED: These are just css for the demo data
    dropdownCssClass : 'capitalize',
    containerCssClass: 'capitalize',

    // NOT NEEDED: text for loading more results
    formatLoadMore   : function() {return 'Loading more...'},

    // query with pagination
    query            : function (q) {
      var pageSize,
        results;
      pageSize = 20; // or whatever pagesize
      var results  = [];
      if (q.term && q.term !== "") {
        // HEADS UP; for the _.filter function i use underscore (actually lo-dash) here
        var results = this.data;
        var results = _.filter(results, function (e) {
            if(typeof e.children != 'undefined')
          {
            subresults = _.filter(e.children, function (f) {
                return (f.text.toUpperCase().indexOf(q.term.toUpperCase()) >= 0);
            });
            if(subresults.length > 0)
                return true;
            return false;
          }
          return (e.text.toUpperCase().indexOf(q.term.toUpperCase()) >= 0);
        });
        newresults = [];
        for (var i = 0, len = results.length; i < len; i++) {
        newresults[i] = {};
        if(typeof results[i].text != 'undefined')
            newresults[i].text = results[i].text;
        if(typeof results[i].id != 'undefined')
            newresults[i].id = results[i].id;
        if(typeof results[i].children != 'undefined')
        {
            newresults[i].children = results[i].children;
            newresults[i].children = _.filter(newresults[i].children, function (f)                          {
                return (f.text.toUpperCase().indexOf(q.term.toUpperCase()) >= 0);
            });
        }
      }
      results = newresults;
      } else if (q.term === "") {
        results = this.data;

      }

      q.callback({
        results: results.slice((q.page - 1) * pageSize, q.page * pageSize),
        more   : results.length >= q.page * pageSize
      });
    }
  });
4
Maulik Vora

Voici une version de travail pour Select2 v4

Basé sur la réponse ici : et modifié pour que la recherche fonctionne avec lo-dash

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

JsFiddle: http://jsfiddle.net/favm4dp9/2/

1
lofihelsinki

Le plus simple fonctionne pour moi est: 

$(".client_id").select2({
 minimumInputLength: 2
  });

Vous pouvez modifier la valeur de minimumInputLength à votre guise.

De cette façon, select2 n'aura pas à afficher la liste complète, mais le résultat obtenu seulement après le nombre fixe de caractères saisis Bien que vous ayez toujours un grand nombre de listes au niveau du code frontal.

De plus, si vous utilisez allowClear, vous devez déclarer un gestionnaire de remplacement comme ceci:

$(".client_id").select2({
            minimumInputLength: 2,
            allowClear: true,
            placeholder: '--Select Client--'
        });

Consultez la documentation ici http://select2.github.io/select2

1
Jaber Al Nahian