43

Sto usando Bootstrap 2.1.1 e jQuery 1.8.1 e sto provando a utilizzare le funzionalità di Typeahead.Twitter Bootstrap Typeahead - Id & Label

cerco di visualizzare un un'etichetta e utilizzare un id come uno standard <select />

ecco la mia inizializzazione typeahead:

$(':input.autocomplete').typeahead({ 
    source: function (query, process) { 
     $('#autocompleteForm .query').val(query); 
     return $.get(
      $('#autocompleteForm').attr('action') 
      , $('#autocompleteForm').serialize() 
      , function (data) { 
       return process(data); 
      } 
     ); 
    } 
}); 

Ecco il genere di JSON che sto inviando

[{"id":1,"label":"machin"},{"id":2,"label":"truc"}] 

Come posso dire process() per visualizzare le mie etichette e memorizzare l'ID selezionato in un altro campo nascosto?

+1

eseguire una delle [commenti qui] (http://stackoverflow.com/questions/11887324/bootstrap-typeahead-ajax- aiuto-valore-da-dati) aiuto? – Owlvark

risposta

75

C'è un ottimo tutorial qui che spiega come fare questo: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/ (leggi il mio commento su quella pagina se non è stato ancora riflesso nella parte principale del post).

basati su tale tutorial, e il JSON che hai fornito, si può fare qualcosa di simile:

$(':input.autocomplete').typeahead({ 
    source: function(query, process) { 
     objects = []; 
     map = {}; 
     var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable 
     $.each(data, function(i, object) { 
      map[object.label] = object; 
      objects.push(object.label); 
     }); 
     process(objects); 
    }, 
    updater: function(item) { 
     $('hiddenInputElement').val(map[item].id); 
     return item; 
    } 
});      
+15

una cosa importante da notare è la variabile 'map' lì e il suo ambito. Secondo il tuo codice è globale insieme alla variabile 'objects'. Ciò significa che è possibile avere solo 1 typeahead sulla pagina alla volta, altrimenti l'oggetto della mappa sarà condiviso tra caselle di tipo typeahead e portare a bug strani. Per avere più teste di tipo dovrai usare una chiusura e definire la variabile della mappa lì. –

+8

"I nomi dei tuoi oggetti devono essere unici per poter funzionare correttamente." Quindi, la loro soluzione non funziona se, per esempio, stai filtrando un elenco di persone che potrebbero avere lo stesso nome. – yayitswei

+0

@yayitswei Questo sarebbe comunque inutile, in quanto l'utente non sarebbe in grado di identificare quale voce è quella giusta. –

3

La risposta selezionata è un po 'un trucco. Stavo cercando la stessa cosa, e questo approccio funziona a meraviglia:

https://github.com/twbs/bootstrap/pull/3682

Mantiene due matrici, una per il nome che typeahead spettacoli, e uno per l'oggetto da cui si estrae il nome. Quando una delle opzioni è selezionata, usa il nome per trovare l'oggetto da cui proviene.

+1

Twitter Bootstrap ha un nuovo percorso su Github. Prova https://github.com/twbs/bootstrap/pull/3682 –

1

Solo un altro modo per implementare la funzione PieRreF.

var separator = "####"; 
$("'.autocomplete'").typeahead({ 
    minLength: 3, 
    source: function (query, process) { 
     var config = { 
      type: 'POST', 
      url: 'Requests/AJAX.PHP', //Change it 
      cache: 'false', 
      data: { 
       query: query 
      }, 
      dataType: 'json' 
     }; 

     config.beforeSend = function() { 
      //TODO : loading gif 
     }; 

     config.error = function (json) { 
      if (json.error) { 
       alert(json.error); 
      } 
     }; 

     config.success = function (json) { 
      if (json.error) { 
       alert(json.error); 
      } 
      var data = []; 
      for (var i = 0; i < json.data.length; i++) { 
       data.push(json.data[i].id + separator + json.data[i].name); 
      } 

      process(data); 
     }; 

     $.ajax(config); 
    }, 
    highlighter: function (item) { 
     var parts = item.split(separator); 
     parts.shift(); 
     return parts.join(separator); 
    }, 
    updater: function (item) { 
     var parts = item.split(separator); 
     $('.autocomplete').val(parts.shift()); 
     return parts.join(separador); 
    } 
}); 
5

Per chiarire quello che stavo dicendo nel mio commento. Se si desidera che più tipi di avanzamento siano nella stessa pagina, è necessario definirne uno in una funzione e creare una variabile di mappa separata per essi.

function initFromField() { 
    var map; 
    $('#from:input.autocomplete').typeahead({ 
     source: function(query, process) { 
      map = {}; 
      var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable 
      objects = constructMap(data, map); 
      process(objects); 
     }, 
     updater: function(item) { 
      $('#hidden-from-input').val(map[item].id); 
      return item; 
     } 
    }); 
} 

function initToField() { 
    var map; 
    $('#to:input.autocomplete').typeahead({ 
     source: function(query, process) { 
      objects = []; 
      map = {}; 
      var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable 
      objects = constructMap(data, map); 
      process(objects); 
     }, 
     updater: function(item) { 
      $('#hidden-to-input').val(map[item].id); 
      return item; 
     } 
    }); 
} 

function constructMap(data, map) { 
    var objects = []; 
    $.each(data, function(i, object) { 
     map[object.label] = object; 
     objects.push(object.label); 
    }); 
    return objects; 
} 

$(function initFields() { 
    initFromField(); 
    initToField(); 
}); 

Nota come ho ambito la variabile di mappa all'interno delle due funzioni di inizializzazione del campo. Questo è importante, assicura che la stessa variabile di mappa non venga utilizzata da entrambi i campi di input.

3

Il problema che ho riscontrato con alcune di queste soluzioni è che la funzione source viene richiamata ripetutamente su ogni evento keyup della casella di input. Significato, gli array sono in fase di costruzione e loop su ogni evento keyup.

Questo non è necessario. Utilizzando una chiusura, è possibile elaborare i dati solo una volta e mantenere un riferimento ad essi all'interno della funzione source. Inoltre, la seguente soluzione risolve il problema dello spazio dei nomi globale della soluzione di @ Gerbus e consente inoltre di giocare con la matrice di dati una volta che l'utente ha selezionato qualcosa (ad esempio, rimuovendo quella voce dall'elenco).

// Setup the auto-complete box of users 
    var setupUserAcUi = function(data) { 
     var objects = []; 
     var map = {}; 
     $.each(data, function(i, object) { 
      map[object.name] = object; 
      objects.push(object.name); 
     }); 

     // The declaration of the source and updater functions, and the fact they 
     // are referencing variables outside their scope, creates a closure 
     $("#splitter-findusers").typeahead({ 
     source: function(query, process) { 
      process(objects); 
     }, 
     updater: function(item) { 
      var mapItem = map[item]; 
      objects.splice($.inArray(item, objects), 1); // Remove from list 
      // Perform any other actions 
     } 
     }); 
    }; 

    // `data` can be an array that you define, 
    // or you could pass `setupUserAcUi` as the callback to a jQuery.ajax() call 
    // (which is actually how I am using it) which returns an array 
    setupUserAcUi(data); 
3

ho lottato con questo problema me stesso, ecco la soluzione mi è venuta, per dati del tipo:

[{'id':an_id, 'name':a_name}] 

Was:

$("#memberSearch").typeahead({ 
      source: function (query, process) { 
       var $this = this //get a reference to the typeahead object 
       return $.get('/getSwimmerListJSON',function(data){ 
        var options = []; 
        $this["map"] = {}; //replace any existing map attr with an empty object 
        $.each(data,function (i,val){ 
         options.push(val.name); 
         $this.map[val.name] = val.id; //keep reference from name -> id 
        }); 
        return process(options); 
       }); 
      }, 
      updater: function (item) { 
       console.log(this.map[item],item); //access it here 

      } 

     }); 
1

selezionato la risposta non riguarda etichette non univoche (ad esempio il nome di una persona). Sto utilizzando il seguente che mantiene la formattazione predefinita evidenziatore:

  var callback = function(id) { 
       console.log(id); 
      }; 

      $('.typeahead',this.el).typeahead({ 
       source: function (query, process) { 

        var sourceData = [ 
         {id:"abc",label:"Option 1"}, 
         {id:"hfv",label:"Option 2"}, 
         {id:"jkf",label:"Option 3"}, 
         {id:"ds",label:"Option 4"}, 
         {id:"dsfd",label:"Option 5"}, 
        ]; 

        var concatSourceData = _.map(sourceData,function(item){ 
         return item.id + "|" + item.label; 
        }); 

        process(concatSourceData); 
       }, 

       matcher : function(item) { 
        return this.__proto__.matcher.call(this,item.split("|")[1]); 
       }, 

       highlighter: function(item) { 
        return this.__proto__.highlighter.call(this,item.split("|")[1]); 
       }, 

       updater: function(item) { 
        var itemArray = item.split("|"); 
        callback(itemArray[0]); 
        return this.__proto__.updater.call(this,itemArray[1]); 
       } 
      }); 
10

A partire dalla versione 0.10.1 di Twitter typeahead (https://github.com/twitter/typeahead.js), Id/Label è supportato nativamente:

$('input[name=address]').typeahead({ 
     hint: false 
    }, { 
     source: function (query, cb) { 
      $.ajax({ 
       url: '/api/addresses?q=' + encodeURIComponent(query), 
       dataType: 'json', 
       cache: false, 
       type: 'GET', 
       success: function (response, textStatus, jqXHR) { 
        cb(response.data); 
       }, 
       error: function (jqXHR, textStatus, errorThrown) { 
       } 
      }); 
     }, 
     name: 'addresses', 
     displayKey: 'text' 
    }).on('typeahead:selected', function (e, suggestion, name) { 
     window.location.href = '/' + suggestion.id; 
    }); 

Se l'esempio sopra, sto passando una serie di oggetti al callback sorgente (cb). Specificando displayKey: 'text', sto dicendo alla libreria di usare la proprietà 'text' per l'auto-suggerimento. Quando viene chiamato il callback "typeahead: select", il secondo argomento passato (suggestion) contiene l'oggetto selezionato.

+0

Questa è una risposta. – VSG24

3

Ecco una soluzione incapsulata. Questa soluzione ti permette di avere più di un typeahead sulla stessa pagina.

Questa è una versione modificata di #13279176 risposta Gerbus.

$('.make-me-typeahead').typeahead({ 
    source: function (query) { 
     var self = this; 
     self.map = {}; 
     var items = []; 

     var data = [ 
      {"id": 1, "label": "machin"}, 
      {"id": 2, "label": "truc"} 
     ]; 

     $.each(data, function (i, item) { 
      self.map[item.label] = item; 
      items.push(item.label) 
     }); 

     return items; 
    }, 

    updater: function (item) { 
     var selectedItem = this.map[item]; 
     this.$element.data('selected', selectedItem); 
     return item; 
    } 
}); 

Ora, quando è necessario ottenere la chiave della voce selezionata corrente basta fare $('.make-me-typeahead').data('selected')

-1

ho fatto un angolare direttiva 2, typeahead-angular2, che fa esattamente ciò che si vuole, e le maniglie il caso di etichette non univoche pure. Puoi prendere la parte typeahead.

Questa direttiva gestisce oggetti complessi con più attributi e gestisce il caso in cui l'etichetta non è univoca. esso riceve fondamentalmente 4 parametri:

  • @Input() name; // nome per typeahead
  • @Input() objectsDataSet; // un dataSet di oggetti, potrebbe essere qualsiasi tipo di oggetto
  • @Input() handleFunction; // una funzione di callback che viene chiamata quando l'oggetto è selezionato, puoi passare l'oggetto o qualsiasi cosa tu voglia a questa funzione.
  • @Input() labelAtt; // l'attributo dell'etichetta (object[labelAtt] viene visualizzato all'utente, deve essere una stringa).

esempio:

<input type="text" class="form-control" placeholder="Name..." typeaheadautocomplete [objectsDataSet]="clientList" [labelAtt]="'Firstname'" [name]="'clients'" [handleFunction]="logClient"> 

come si può vedere: clientList è un array di oggetti "client", diciamo dire {"Fistname":"Billel","Lastname":"Guerfa",....} usiamo l'attributo Nome per la lista di completamento automatico. logClient qui riceve un oggetto client e lo visualizza.

Dipendenze:

appena dichiarano lo script typeahead a livello index.html.

See: https://github.com/BillelGuerfa/typeahead-angular2/

Problemi correlati