Javascript Twitter Bootstrap Typeahead - Id 和标签
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12389948/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Twitter Bootstrap Typeahead - Id & Label
提问by Pierre de LESPINAY
I'm using Bootstrap 2.1.1 and jQuery 1.8.1 and trying to use Typeahead's functionality.
我正在使用 Bootstrap 2.1.1 和 jQuery 1.8.1 并尝试使用 Typeahead 的功能。
I try to display a labeland use an idlike a standard <select />
我尝试显示一个标签并像标准一样使用id<select />
Here is my typeahead initialization:
这是我的预输入初始化:
$(':input.autocomplete').typeahead({
source: function (query, process) {
$('#autocompleteForm .query').val(query);
return $.get(
$('#autocompleteForm').attr('action')
, $('#autocompleteForm').serialize()
, function (data) {
return process(data);
}
);
}
});
Here is the kind of JSON that I'm sending
这是我发送的那种 JSON
[{"id":1,"label":"machin"},{"id":2,"label":"truc"}]
How can I tell process()
to display my labels and store the selected ID in another hidden field?
我怎么知道process()
显示我的标签并将选定的 ID 存储在另一个隐藏字段中?
回答by Gerbus
There's a great tutorial here that explains how to do this: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/(read my comment on that page if it hasn't been reflected yet in the main part of the post).
这里有一个很棒的教程解释了如何做到这一点:http: //tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/(如果没有,请阅读我对该页面的评论尚未反映在帖子的主要部分)。
Based on that tutorial, and the JSON you provided, you can do something like this:
根据该教程和您提供的 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;
}
});
回答by Johnny Oshika
As of version 0.10.1 of Twitter Typeahead (https://github.com/twitter/typeahead.js), Id / Label is supported natively:
从 Twitter Typeahead ( https://github.com/twitter/typeahead.js) 0.10.1 版本开始,本机支持 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;
});
If the example above, I'm passing an array of objects to the source callback (cb). By specifying displayKey: 'text', I'm telling the library to use the 'text' property for the auto-suggest. When the 'typeahead:select' callback is called, the second argument passed in (suggestion) contains the object that was selected.
如果是上面的例子,我将一个对象数组传递给源回调(cb)。通过指定 displayKey: 'text',我告诉库使用 'text' 属性进行自动建议。当调用 'typeahead:select' 回调时,传入的第二个参数(建议)包含被选择的对象。
回答by Michael Yagudaev
To clarify what I was saying in my comment. If you wanted multiple type aheads on the same page you need to define each in a function and create a separate map variable for them.
为了澄清我在评论中所说的内容。如果您希望在同一页面上显示多个类型,则需要在函数中定义每个类型并为它们创建单独的映射变量。
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 how I scoped the map variable inside the two field initialization functions. This is important, it makes sure the same map variable is not used by both input fields.
请注意我如何在两个字段初始化函数内确定 map 变量的范围。这很重要,它确保两个输入字段不使用相同的映射变量。
回答by HennyH
I've been struggling with this problem myself, here is the solution I came up with, for data of the type:
我自己一直在努力解决这个问题,这是我想出的解决方案,适用于以下类型的数据:
[{'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
}
});
回答by vcardillo
The problem I have seen with some of these solutions, is that the source
function is called repeatedly on every keyup event of the input box. Meaning, the arrays are being built and looped over on every keyup event.
我在其中一些解决方案中看到的问题是,source
在输入框的每个 keyup 事件上都会重复调用该函数。这意味着,数组正在构建并在每个 keyup 事件上循环。
This is not necessary. Using a closure, you can process the data only once, and maintain a reference to it from within the source
function. In addition, the following solution solves the global namespace problem of @Gerbus's solution, and also allows you to play with the array of data once the user has selected something (for example, removing that item from the list).
这是没有必要的。使用闭包,您只能处理数据一次,并在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);
回答by Kevin Lawrence
The selected answer is a bit of a hack. I was looking for the same thing, and this approach works beautifully:
选择的答案有点像黑客。我一直在寻找同样的东西,这种方法效果很好:
https://github.com/twbs/bootstrap/pull/3682
https://github.com/twbs/bootstrap/pull/3682
It keeps two arrays, one for the name that typeahead shows, and one for the object from which the name is extracted. When one of the options is selected, it uses the name to find the object from whence it came.
它保留两个数组,一个用于预先输入显示的名称,另一个用于从中提取名称的对象。选择其中一个选项时,它将使用该名称来从它来源中找到对象。
回答by Capy
Here is an encapsulated solution. This solution allows you have more than one typeahead on the same page.
这是一个封装的解决方案。此解决方案允许您在同一页面上有多个预先输入。
This is a modified version of #13279176Gerbus answer.
这是#13279176Gerbus 答案的修改版本。
$('.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;
}
});
Now when you need get the key of the current selected item you just need do $('.make-me-typeahead').data('selected')
现在,当您需要获取当前所选项目的密钥时,您只需要做 $('.make-me-typeahead').data('selected')
回答by Pedro Muniz
Just another way to implement Pierref function.
实现 Pierreref 函数的另一种方式。
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);
}
});
回答by will.ogden
The selected answer doesn't deal with non unique labels (e.g. a person's name). I'm using the following which keeps the default highlighter formatting:
所选答案不处理非唯一标签(例如人名)。我正在使用以下保留默认荧光笔格式的内容:
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]);
}
});
回答by Billel Guerfa
I made an Angular 2 directive, typeahead-angular2, that does exactly what you want, and handles the case of non-unique labels as well. You can take the typeahead part.
我创建了一个 Angular 2 指令typeahead-angular2,它完全符合您的要求,并且还处理非唯一标签的情况。您可以使用预先输入的部分。
This directive handle complexe objects with multiple attributes and handle the case where the label isn't unique. it basicly recieves 4 parameters :
@Input() name;
//name for typeahead@Input() objectsDataSet;
// a dataSet of objects , it could be any kind of object@Input() handleFunction;
// a callback function that is called when the object is selected , you can pass the object or whatever you want to this function.@Input() labelAtt;
// the label attribute (object[labelAtt]
is displayed to the user , it must be a string).example :
<input type="text" class="form-control" placeholder="Name..." typeaheadautocomplete [objectsDataSet]="clientList" [labelAtt]="'Firstname'" [name]="'clients'" [handleFunction]="logClient">
as you can see :
clientList
is an array of "client" objects , let's say{"Fistname":"Billel","Lastname":"Guerfa",....}
we use the Firstname attribute for the autocomplete list.logClient
here recieves a client object and displays it.Dependencies :
just declare the typeahead script at the index.html level.
- typeahead : https://twitter.github.io/typeahead.js/
该指令处理具有多个属性的复杂对象并处理标签不唯一的情况。它基本上接收 4 个参数:
@Input() name;
//预先输入的名称@Input() objectsDataSet;
// 一个对象的数据集,它可以是任何类型的对象@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
这里接收一个客户端对象并显示它。依赖项:
只需在 index.html 级别声明 typeahead 脚本。