javascript jquery twitter-bootstrap autocomplete typeahead.js

javascript - Twitter Bootstrap Typeahead-Id y etiqueta



jquery twitter-bootstrap (10)

Estoy usando Bootstrap 2.1.1 y jQuery 1.8.1 y estoy intentando usar la funcionalidad de Typeahead.

Intento mostrar una etiqueta y usar una identificación como un <select /> estándar

Aquí está mi inicialización tersa:

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

Aquí está el tipo de JSON que estoy enviando

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

¿Cómo puedo decirle a process() que muestre mis etiquetas y almacene la identificación seleccionada en otro campo oculto?


Aquí hay un excelente tutorial que explica cómo hacerlo: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/ (lea mi comentario en esa página si no lo ha hecho) se ha reflejado aún en la parte principal de la publicación).

Según ese tutorial y el JSON que proporcionó, puede hacer algo como esto:

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


Simplemente otra forma de implementar la función de 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); } });


Para aclarar lo que estaba diciendo en mi comentario. Si desea varios encabezados de tipo en la misma página, necesita definir cada uno en una función y crear una variable de mapa separada para ellos.

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

Tenga en cuenta cómo exploré la variable de mapa dentro de las dos funciones de inicialización de campo. Esto es importante, se asegura de que los dos campos de entrada no usen la misma variable de mapa.


El problema que he visto con algunas de estas soluciones es que la función de source se invoca repetidamente en cada evento keyup del cuadro de entrada. Lo que significa que las matrices se están construyendo y bucleando en cada evento keyup.

Esto no es necesario. Con un cierre, puede procesar los datos solo una vez y mantener una referencia desde la función de source . Además, la siguiente solución resuelve el problema del espacio de nombres global de la solución de @ Gerbus, y también le permite jugar con la matriz de datos una vez que el usuario ha seleccionado algo (por ejemplo, eliminar ese elemento de la lista).

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


La respuesta seleccionada es un poco pirata. Estaba buscando lo mismo, y este enfoque funciona maravillosamente:

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

Mantiene dos matrices, una para el nombre que muestra typeahead, y otra para el objeto del que se extrae el nombre. Cuando se selecciona una de las opciones, usa el nombre para encontrar el objeto de donde vino.


La respuesta seleccionada no trata con etiquetas no únicas (por ejemplo, el nombre de una persona). Estoy usando lo siguiente que mantiene el formateo del resaltador predeterminado:

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


A partir de la versión 0.10.1 de Twitter Typeahead ( https://github.com/twitter/typeahead.js ), Id / Label es compatible de forma nativa:

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

Si el ejemplo anterior, estoy pasando una matriz de objetos a la devolución de llamada de origen (cb). Al especificar displayKey: ''text'', le digo a la biblioteca que use la propiedad ''text'' para la sugerencia automática. Cuando se llama a ''typeahead: select'' callback, el segundo argumento pasado (sugerencia) contiene el objeto que se seleccionó.


Hice una directiva Angular 2, typeahead-angular2 , que hace exactamente lo que quiere, y también maneja el caso de etiquetas no exclusivas. Puedes tomar la parte de escribir por adelantado.

Esta directiva maneja objetos complejos con múltiples atributos y maneja el caso donde la etiqueta no es única. Básicamente recibe 4 parámetros:

  • @Input() name; // nombre para typeahead
  • @Input() objectsDataSet; // un conjunto de datos de objetos, podría ser cualquier tipo de objeto
  • @Input() handleFunction; // una función de devolución de llamada que se llama cuando se selecciona el objeto, puede pasar el objeto o lo que quiera a esta función.
  • @Input() labelAtt; // el atributo de etiqueta ( object[labelAtt] se muestra al usuario, debe ser una cadena).

ejemplo:

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

como puede ver: clientList es una matriz de objetos "clientes", digamos {"Fistname":"Billel","Lastname":"Guerfa",....} usamos el atributo Firstname para la lista de autocompletar. logClient aquí recibe un objeto de cliente y lo muestra.

Dependencias:

solo declare el script typeahead en el nivel index.html.

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


He estado luchando con este problema yo mismo, aquí está la solución que se me ocurrió, para datos del tipo:

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

Estaba:

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


Aquí hay una solución encapsulada. Esta solución le permite tener más de un encabezado en la misma página.

Esta es una versión modificada de # 13279176 Respuesta de 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; } });

Ahora, cuando necesite obtener la clave del elemento seleccionado actual, solo necesita hacer $(''.make-me-typeahead'').data(''selected'')