2015-09-24 25 views
7

Sto usando select2 con adattatore dati personalizzato. Tutti i dati forniti a select2 vengono generati localmente nella pagina Web (quindi non è necessario utilizzare ajax). Poiché il metodo query può generare un sacco di risultati (circa 5k) l'apertura della casella di selezione è piuttosto lenta.Come abilitare lo scrolling infinito in select2 4.0 senza ajax

Come rimedio, volevo usare lo scroll infinito. Documentation per l'adattatore dati personalizzati dice che query metodo dovrebbe ricevere page parametro insieme a term:

@param params.page La pagina specifica che deve essere caricato. Questo è tipicamente fornito quando si lavora con insiemi di dati remoti, che si basano su paginazione per determinare quali oggetti devono essere visualizzati.

Ma non è così: è presente solo term. Ho provato a restituire more: true o more: 1000, ma questo non ha aiutato. Immagino sia perché, per impostazione predefinita, infinite scroll is enabled iff ajax is enabled.

Suppongo che l'abilitazione dello scroll infinito comporterà l'utilizzo di amd.require, ma non sono sicuro di cosa fare esattamente. Ho provato questo codice:

Questa è una sceneggiatura per il caffè, ma spero che sia leggibile per tutti. input è DOM elemento contenente casella di selezione - ho già fatto input.select2(//options)

La mia domanda è, fondamentalmente, non effettuato scroll infinito senza ajax?

+0

Sarei molto interessato a una risposta a questo. Hai scoperto qualcosa? –

+1

@happytimeharry Sì, l'ho fatto. Ho descritto la mia soluzione nella risposta. Spero possa essere d'aiuto! –

risposta

9

Select2 abilita lo scorrimento illimitato solo se ajax è abilitato. Fortunatamente possiamo abilitarlo e utilizzare ancora il nostro adattatore. Quindi mettere l'oggetto vuoto nell'opzione ajax farà il trucco.

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

Avanti, definire il proprio adattatore di dati. Al suo interno, la locanda query invia le informazioni pagination in callback.

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

Ecco un full fiddle

+0

Questo è killer, grazie mille per aver trovato questo !! –

+1

La ricerca sembra essere rotta con questa soluzione? – prograhammer

+1

@prograhammer ho ampliato la risposta per mostrare come mantenere intatta la ricerca qui http://stackoverflow.com/a/33174942/152640 –

7

Ampliando this answer per mostrare come mantenere la funzionalità di ricerca che viene fornito con select2. Grazie Paperback Writer!

Riferito anche a this example su come ottenere lo scrolling infinito utilizzando un'origine dati lato client, con select2 versione 3.4.5.

Questo esempio utilizza le opzioni oringali in un tag select per creare l'elenco anziché l'array di articoli, che è ciò che è stato richiesto nella mia situazione.

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

Ecco un jsfiddle

+1

Puoi fornire un jsFiddle funzionante? Nemmeno io riesco a far funzionare questo. – prograhammer

+0

@prograhammer ci vai Homie –

+0

LOL, ho quasi finito di creare un violino per te! Finalmente l'ho fatto funzionare! – prograhammer

8

ho sentito le risposte di cui sopra necessaria la dimostrazione migliore. Select2 4.0.0 introduces la possibilità di fare personalizzato adapters.Utilizzando il trucco ajax: {}, ho creato un DataAdapter personalizzato jsonAdapter che utilizza direttamente JSON locale. Si noti inoltre come la versione 4.0.0 di Select2 abbia prestazioni impressionanti utilizzando una grande stringa JSON. Ho usato uno online JSON generator e ho creato 10.000 nomi come dati di test. Tuttavia, questo esempio è molto fangoso. Mentre funziona, mi auguro che ci sia un modo migliore.

vedere il pieno violino qui: 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

Bello! Grazie a @prograhammer –

+4

Vorrei poter votare più di 10.000 volte. Sono sicuro che c'è una buona ragione, ma sembra che v4 sia troppo ingegnerizzato. Ci sono volute ore per capire, ma per fortuna mi sono imbattuto nella tua risposta. Grazie @prograhammer – user1447679

+0

Questo è un ottimo esempio di adattatore. Tuttavia, sto cercando di capire il modo migliore per mappare in altri valori di oggetti personalizzati. Normalmente, puoi recuperare $ (selector) .select2 ("data") e ottenere cose diverse da id e text, ma questo adattatore limita quella parte. – Mark

0

Questa non è una risposta diretta: dopo aver lottato molto con questo per un po ', ho finito per passare a selectize. Il supporto di Select2 per la ricerca non Ajax, dalla versione 4, è terribilmente complicato, confinante con il ridicolo, e non ben documentato. Selectize ha un supporto esplicito per la ricerca non Ajax: si implementa semplicemente una funzione che restituisce una lista.

Problemi correlati