Twitter Bootstrap Typeahead-Id & Label
J'utilise Bootstrap 2.1.1 et jQuery 1.8.1 et j'essaie d'utiliser la fonctionnalité de Typeahead.
j'essaie d'afficher un étiquette et d'utiliser un id comme une norme <select />
Voici mon initialisation typeahead:
$(':input.autocomplete').typeahead({
source: function (query, process) {
$('#autocompleteForm .query').val(query);
return $.get(
$('#autocompleteForm').attr('action')
, $('#autocompleteForm').serialize()
, function (data) {
return process(data);
}
);
}
});
voici le genre de JSON que j'envoie
[{"id":1,"label":"machin"},{"id":2,"label":"truc"}]
Comment dire process()
pour afficher mes étiquettes et stocker L'ID sélectionné dans un autre champ caché?
10 réponses
il y a un grand tutoriel ici qui explique comment faire ceci: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead / (lire mon commentaire sur cette page si elle n'a pas encore été reflétée dans la partie principale du post).
basé sur ce tutoriel, et le JSON que vous avez fourni, vous pouvez faire quelque chose comme ceci:
$(':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;
}
});
depuis la version 0.10.1 de Twitter Typeahead ( https://github.com/twitter/typeahead.js ), Id / Label est supporté nativement:
$('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 l'exemple ci-dessus, je passe un tableau d'objets à la source callback (cb). En spécifiant displayKey:' text', je dis à la bibliothèque d'utiliser la propriété' text ' pour l'auto-suggest. Lorsque le callback' typeahead:select ' est appelé, le second argument passé dans (suggestion) contient objet qui a été sélectionné.
pour clarifier ce que je disais dans mon commentaire. Si vous voulez plusieurs têtes de type a sur la même page, vous devez définir chacune dans une fonction et créer une variable de carte séparée pour eux.
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();
});
Note comment j'ai scopé la variable map à l'intérieur des deux fonctions d'initialisation de champ. Ceci est important, il s'assure que la même variable map n'est pas utilisée par les deux champs d'entrée.
le problème que j'ai vu avec certaines de ces solutions, est que la fonction source
est appelée à plusieurs reprises sur chaque événement de la boîte de saisie. Sens, les tableaux sont construits et mis en boucle sur chaque événement keyup.
Ce n'est pas nécessaire. En utilisant une fermeture, vous pouvez traiter les données une seule fois, et maintenir une référence à partir de la fonction source
. En outre, la solution suivante résout le problème d'espace de noms global de @Gerbus solution, et vous permet également de jouer avec le tableau de données une fois que l'utilisateur a sélectionné quelque chose (par exemple, en supprimant cet élément de la liste).
// 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 réponse choisie est un peu un hack. Je cherchais la même chose, et cette approche fonctionne à merveille:
https://github.com/twbs/bootstrap/pull/3682
il conserve deux tableaux, un pour le nom que typeahead montre, et un pour l'objet dont le nom est extrait. Quand une des options est sélectionnée, elle utilise le nom pour trouver l'objet d'où il vient.
Voici une solution encapsulée. Cette solution vous permet d'avoir plus d'un type d'en-tête sur la même page.
Ceci est une version modifiée de #13279176 Gerbus réponse.
$('.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;
}
});
Maintenant, quand vous avez besoin d'obtenir la clé de l'actuel article sélectionné, vous avez juste besoin de faire $('.make-me-typeahead').data('selected')
j'ai été aux prises avec ce problème moi-même, voici la solution que j'ai trouvé, pour les données du type:
[{'id':an_id, 'name':a_name}]
était:
$("#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
}
});
juste une autre façon d'implémenter la fonction 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);
}
});
la réponse choisie ne traite pas des étiquettes non uniques (p. ex. le nom d'une personne). J'utilise ce qui suit qui conserve le formatage par défaut du surligneur:
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]);
}
});
j'ai fait une directive angulaire 2, typeahead-angular2 , qui fait exactement ce que vous voulez, et gère le cas des étiquettes non uniques ainsi. Vous pouvez prendre le typeahead partie.
cette directive traite les objets complexes avec plusieurs attributs et gérer le cas où l'étiquette n'est pas unique. il reçoit basicly 4 paramètres:
@Input() name;
//nom de l'auteur@Input() objectsDataSet;
/ / un ensemble de données d'objets , il pourrait s'agir de n'importe quel type d'objet@Input() handleFunction;
/ / une fonction de rappel appelée lorsque l'objet est sélectionné , vous pouvez passer l'objet ou ce que vous voulez pour cette fonction.@Input() labelAtt;
/ / l'attribut étiquette (object[labelAtt]
est affiché à l'utilisateur , il doit s'agir d'une chaîne de caractères).exemple:
<input type="text" class="form-control" placeholder="Name..." typeaheadautocomplete [objectsDataSet]="clientList" [labelAtt]="'Firstname'" [name]="'clients'" [handleFunction]="logClient">
comme vous pouvez le voir:
clientList
est un tableau d'objets "client", dites{"Fistname":"Billel","Lastname":"Guerfa",....}
nous utilisons le Attribut Firstname pour la liste autocomplete.logClient
ici recieves un client de l'objet et l'affiche.dépendances:
il suffit de déclarer le script Type Head à l'index.niveau de html.
- typeahead: https://twitter.github.io/typeahead.js /