2015-09-24 8 views
7

Ich benutze select2 mit benutzerdefinierten Datenadapter. Alle Daten, die an select2 übergeben werden, werden lokal in der Webseite generiert (also keine Notwendigkeit, ajax zu verwenden). Als query Methode kann eine Menge von Ergebnissen (ca. 5k) erstellen, die Auswahlbox ist ziemlich langsam.Wie unendlich scrollen in select2 4.0 ohne Ajax

Als Abhilfe wollte ich unendlich scroll verwenden. Documentation für benutzerdefinierte Datenadapter sagt, dass query Methode page Parameter zusammen mit term erhalten soll:

@param params.page Die spezifische Seite, die geladen werden soll. Dies ist normalerweise bei der Arbeit mit Remote-Datensätzen, die auf Seitenumbruch verlassen, um festzustellen, welche Objekte angezeigt werden sollen.

Aber es ist nicht: nur term ist vorhanden. Ich habe versucht, more: true oder more: 1000 zurückgeben, aber das hat nicht geholfen. Ich denke, das liegt daran, dass standardmäßig infinite scroll is enabled iff ajax is enabled.

Ich rate, dass die Aktivierung der unendlichen Scroll wird mit amd.require, aber ich bin mir nicht sicher, was genau zu tun. Ich habe diesen Code versucht:

Dies ist Kaffee Skript, aber ich hoffe, dass es für alle lesbar ist. input ist DOM Element Auswahlbox enthält - ich früher input.select2(//options) tat

Meine Frage ist im Grunde, wie aktiviere ich unendlich Scroll ohne ajax?

+0

Ich wäre sehr an einer Antwort darauf interessiert. Hast du etwas herausgefunden? –

+1

@happytimeharry Ja, tat ich. Ich habe meine Lösung in der Antwort beschrieben. Ich hoffe, es hilft! –

Antwort

9

Select2 aktiviert nur unendlich Scroll, wenn ajax aktiviert ist. Glücklicherweise können wir es aktivieren und weiterhin unseren eigenen Adapter verwenden. Wenn Sie also ein leeres Objekt in die ajax Option setzen, ist das der Trick.

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

Als nächstes definieren Sie Ihren eigenen Datenadapter. Im Inneren, Inn query Push pagination Info in Rückruf.

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

Hier ist ein full fiddle

+0

Das ist Killer, vielen Dank für das Finden !! –

+1

Suchen scheint mit dieser Lösung gebrochen zu sein? – prograhammer

+1

@prograhammer Ich erweiterte auf die Antwort, um zu zeigen, wie Suche hier intakt zu halten http://StackOverflow.com/a/33174942/152640 –

7

auf this answer Erweiterung zu zeigen, wie die Suchfunktion zu erhalten, die mit select2 kommt. Danke Paperback Writer!

Wird auch auf this example Bezug genommen, wie Sie mit einer clientseitigen Datenquelle mit select2 Version 3.4.5 unbegrenztes Scrollen erreichen können.

In diesem Beispiel werden die oringal-Optionen in einem select-Tag verwendet, um die Liste anstelle des Elementarrays zu erstellen, was in meiner Situation erforderlich ist.

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

Hier ist ein jsfiddle

+1

Können Sie eine funktionierende jsFiddle bereitstellen? Ich kann das auch nicht funktionieren. – prograhammer

+0

@prograhammer dort gehst du homie –

+0

LOL, ich bin fast fertig mit der Schaffung einer Geige für Sie! Ich habe es endlich funktioniert! – prograhammer

8

ich die Antworten oben benötigt bessere Demonstration fühlte. Select2 4.0.0 introduces die Fähigkeit, benutzerdefinierte adapters zu tun.Unter Verwendung des ajax: {} Tricks habe ich einen benutzerdefinierten dataAdapter jsonAdapter erstellt, der lokalen JSON direkt verwendet. Beachten Sie auch, dass die Version 4.0.0 von Select2 eine beeindruckende Leistung mit einer großen JSON-Zeichenfolge bietet. Ich habe eine online JSON generator verwendet und 10.000 Namen als Testdaten erstellt. Dieses Beispiel ist jedoch sehr schlammig. Während das funktioniert, würde ich hoffen, dass es einen besseren Weg gibt.

Die gesamte Geige hier: 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'); 
+0

Schön! Danke @prograhammer –

+4

Ich wünschte ich könnte dies mehr als 10.000 Mal abstimmen. Ich bin mir sicher, dass es einen guten Grund gibt, aber es scheint, dass v4 überentwickelt ist. Das hat Stunden gedauert, aber glücklicherweise bin ich über deine Antwort gestolpert. Vielen Dank @prograhammer – user1447679

+0

Dies ist ein großartiges Adapterbeispiel. Ich versuche jedoch herauszufinden, wie andere benutzerdefinierte Objektwerte am besten abgebildet werden können. Normalerweise können Sie die $ (selector) .select2 ("data") abrufen und andere Dinge als ID und Text abrufen, aber dieser Adapter begrenzt diesen Teil. – Mark

0

Dies ist keine direkte Antwort: Nach viel mit diesem für eine Weile zu kämpfen, ich selectize Schalte endete. Die Unterstützung von Select2 für Nicht-Ajax-Suche ist seit Version 4 furchtbar kompliziert, grenzt an das Lächerliche und ist nicht gut dokumentiert. Selectize bietet explizite Unterstützung für Nicht-Ajax-Suche: Sie implementieren einfach eine Funktion, die eine Liste zurückgibt.