Twitter Bootstrap Typeahead - идентификатор и ярлык
Я использую Bootstrap 2.1.1 и jQuery 1.8.1 и пытаюсь использовать функции Typeahead.
Я пытаюсь отобразить ярлык и использовать id как стандартный <select />
Вот моя инициализация typeahead:
$(':input.autocomplete').typeahead({
source: function (query, process) {
$('#autocompleteForm .query').val(query);
return $.get(
$('#autocompleteForm').attr('action')
, $('#autocompleteForm').serialize()
, function (data) {
return process(data);
}
);
}
});
Вот такой JSON, который я отправляю
[{"id":1,"label":"machin"},{"id":2,"label":"truc"}]
Как я могу сказать process()
отображать мои метки и сохранить выбранный идентификатор в другом скрытом поле?
Ответы
Ответ 1
Здесь есть отличный учебник, в котором объясняется, как это сделать: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/ (прочитайте мой комментарий на этой странице, если он еще не отражен в главном часть сообщения).
Основываясь на этом учебнике и предоставленном JSON, вы можете сделать что-то вроде этого:
$(':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;
}
});
Ответ 2
Начиная с версии 0.10.1 в Twitter Typeahead (https://github.com/twitter/typeahead.js), Id/Label поддерживается изначально:
$('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;
});
Если приведенный выше пример, я передаю массив объектов для обратного вызова источника (cb). Указав displayKey: "text", я говорю библиотеке использовать свойство "text" для автоматического предложения. Когда вызывается callback 'typeahead: select', второй аргумент, переданный в (предложение), содержит выбранный объект.
Ответ 3
Чтобы прояснить, что я говорил в своем комментарии. Если вы хотите, чтобы на той же странице выполнялось несколько типов, вам необходимо определить их в функции и создать для них отдельную переменную.
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();
});
Обратите внимание, как я применил переменную карты внутри двух функций инициализации поля. Это важно, он гарантирует, что одна и та же переменная карты не будет использоваться обоими полями ввода.
Ответ 4
Выбранный ответ немного взломан. Я искал то же самое, и этот подход работает красиво:
https://github.com/twbs/bootstrap/pull/3682
Он хранит два массива: один для имени, который показывает typeahead, и один для объекта, из которого извлекается имя. Когда выбран один из параметров, он использует имя для поиска объекта, откуда он пришел.
Ответ 5
Проблема, которую я видел с некоторыми из этих решений, заключается в том, что функция source
вызывается многократно в каждом событии keyup в поле ввода. Значение, массивы строятся и зацикливаются на каждом событии keyup.
Это необязательно. Используя замыкание, вы можете обрабатывать данные только один раз и поддерживать ссылку на него из функции source
. Кроме того, следующее решение решает проблему глобального пространства имен решения @Gerbus, а также позволяет вам играть с массивом данных, как только пользователь выбрал что-то (например, удалив этот элемент из списка).
// 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);
Ответ 6
Я сам боролся с этой проблемой, вот решение, которое я придумал, для данных типа:
[{'id':an_id, 'name':a_name}]
Был:
$("#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
}
});
Ответ 7
Вот инкапсулированное решение. Это решение позволяет вам иметь более одного типа на одной странице.
Это измененная версия #13279176 ответа 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;
}
});
Теперь, когда вам нужно получить ключ текущего выбранного элемента, вам просто нужно $('.make-me-typeahead').data('selected')
Ответ 8
Еще один способ реализовать функцию 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);
}
});
Ответ 9
Выбранный ответ не относится к уникальным ярлыкам (например, имя человека). Я использую следующее, которое сохраняет форматирование по умолчанию:
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
Я сделал директиву Angular 2, typeahead- angular2, которая делает именно то, что вы хотите, и обрабатывает случай неидеальных меток. Вы можете взять часть typeahead.
Эта директива обрабатывает сложные объекты с несколькими атрибутами и обрабатывать случай, когда метка не уникальна. он в основном получает 4 параметры:
-
@Input() name;
//name для typeahead -
@Input() objectsDataSet;
//dataSet объектов, это может быть любой объект -
@Input() handleFunction;
//функция обратного вызова, вызываемая при выборе объекта, вы можете передать объект или что угодно к этой функции. -
@Input() labelAtt;
//атрибут метки (object[labelAtt]
отображается пользователю, он должен быть строкой).
пример:
<input type="text" class="form-control" placeholder="Name..." typeaheadautocomplete [objectsDataSet]="clientList" [labelAtt]="'Firstname'" [name]="'clients'" [handleFunction]="logClient">
как вы можете видеть: clientList
- это массив объектов "клиента", давайте скажем {"Fistname":"Billel","Lastname":"Guerfa",....}
, мы используем Атрибут firstname для списка автозаполнения. logClient
здесь получает клиентский объект и отображает его.
Зависимости:
просто объявите typeahead script на уровне index.html.
Смотрите: https://github.com/BillelGuerfa/typeahead-angular2/