可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to use twitter bootstrap to get the manufacturers from my DB.
Because twitter bootstrap typeahead does not support ajax calls I am using this fork:
https://gist.github.com/1866577
In that page there is this comment that mentions how to do exactly what I want to do. The problem is when I run my code I keep on getting:
Uncaught TypeError: Cannot call method 'toLowerCase' of undefined
I googled around and came tried changing my jquery file to both using the minified and non minified as well as the one hosted on google code and I kept getting the same error.
My code currently is as follows:
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
var manufacturers = new Array;
$.map(results.data.manufacturers, function(data, item){
var group;
group = {
manufacturer_id: data.Manufacturer.id,
manufacturer: data.Manufacturer.manufacturer
};
manufacturers.push(group);
});
typeahead.process(manufacturers);
}
});
},
property: 'name',
items:11,
onselect: function (obj) {
}
});
on the url field I added the
window.location.origin
to avoid any problems as already discussed on another question
Also before I was using $.each()
and then decided to use $.map()
as recomended Tomislav Markovski in a similar question
Anyone has any idea why I keep getting this problem?!
Thank you
回答1:
Typeahead expect a list of string as source
$('#manufacturer').typeahead({
source : ["item 1", "item 2", "item 3", "item 4"]
})
In your case you want to use it with a list of objects. This way you'll have to make some changes to make it works
This should works :
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
var manufacturers = new Array;
$.map(results.data.manufacturers, function(data){
var group;
group = {
manufacturer_id: data.Manufacturer.id,
manufacturer: data.Manufacturer.manufacturer,
toString: function () {
return JSON.stringify(this);
},
toLowerCase: function () {
return this.manufacturer.toLowerCase();
},
indexOf: function (string) {
return String.prototype.indexOf.apply(this.manufacturer, arguments);
},
replace: function (string) {
return String.prototype.replace.apply(this.manufacturer, arguments);
}
};
manufacturers.push(group);
});
typeahead.process(manufacturers);
}
});
},
property: 'manufacturer',
items:11,
onselect: function (obj) {
var obj = JSON.parse(obj);
// You still can use the manufacturer_id here
console.log(obj.manufacturer_id);
return obj.manufacturer;
}
});
回答2:
In my case, I was getting this exact error, and it turned out that the version of Bootstrap I was using (2.0.4) did not support passing in a function to the source
setting.
Upgrading to Bootstrap 2.1.1 fixed the problem.
回答3:
UPDATED / REVISED LOOK AT THE ISSUE: The error you mentioned "Cannot call method 'toLowerCase' of undefined" occurred to me when I used the original Typeahead extension in bootstrap that does not support AJAX. (as you have found) Are you sure that the original typeahead extension isn't loading, instead of your revised one?
I have been sucessfully using this Gist of typeahead that is a slight variation on the one you mention. Once I switched to that Gist and confirmed that the input data was good (testing that the input was a string array in an JS object, the issue went away.
Hope this helps
Original answer:
The reason the error occurs is because the value passed into the typeahead matcher function is undefined. That is just a side effect to the real issue which occurs somewhere between your input and that matcher function. I suspect the 'manufacturers' array has a problem. Test it first to verify you have a valid array.
// It appears your array constructor is missing ()
// try the following in your binding code:
var manufacturers = new Array();
Here is what I am using to bind the input to typeahead. I confirmed that it works with your modified typeahead fork.
My HTML:
<!-- Load bootstrap styles -->
<link href="bootstrap.css" rel="stylesheet" type="text/css" />
...
<input type="text" class="typeahead" name="Category" id="Category" maxlength="100" value="" />
...
<!-- and load jQuery and bootstrap with modified typeahead AJAX code -->
<script src="jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="bootstrap-modified-typeahead.js" type="text/javascript"></script>
My binding JavaScript code:
// Matches the desired text input ID in the HTML
var $TypeaheadInput = $("#Category");
// Modify this path to your JSON source URL
// this source should return a JSON string array like the following:
// string[] result = {"test", "test2", "test3", "test4"}
var JsonProviderUrl = "../CategorySearch";
// Bind the input to the typeahead extension
$TypeaheadInput.typeahead({
source: function (typeahead, query) {
return $.post(JsonProviderUrl, { query: query }, function (data) {
return typeahead.process(data);
});
}
});
回答4:
In my case I had null values in my source array causing this error.
Contrived example:
source : ["item 1", "item 2", null, "item 4"]
回答5:
Your manufacturer objects don't have a "name" property, you should change
property: 'name',
to
property: 'manufacturer',
回答6:
Have you tried using mapping variables like example below, you need to use this when you got more then one property in your object;
source: function (query, process) {
states = [];
map = {};
var data = [
{"stateCode": "CA", "stateName": "California"},
{"stateCode": "AZ", "stateName": "Arizona"},
{"stateCode": "NY", "stateName": "New York"},
{"stateCode": "NV", "stateName": "Nevada"},
{"stateCode": "OH", "stateName": "Ohio"}
];
$.each(data, function (i, state) {
map[state.stateName] = state;
states.push(state.stateName);
});
process(states);
}
回答7:
I stumbled upon this issue a while ago. I advice you to recheck configuration where you are including typeahead
libraries (via main.js, app.js or config.js).
Otherwise, you can overwrite the latest Bootstrap version to your application library.
回答8:
Try this code:
String.prototype.hashCode = function(){
var hash = 0;
if (this.length == 0) return hash;
for (i = 0; i < this.length; i++) {
char = this.charCodeAt(i);
hash = ((hash<<5)-hash)+char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
var map_manufacter, result_manufacters;
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
result_manufacter = [], map_manufacters = {};
$.each(results.data.manufacturers, function(item, data){
map_manufacters[data.Manufacturer.manufacturer.hashCode()] = data;
result_manufacters.push(data.Manufacter.manufacter);
});
typeahead.process(result_manufacters);
}
});
},
property: 'name',
items:11,
onselect: function (obj) {
var hc = obj.hashCode();
console.log(map_manufacter[hc]);
}
});
回答9:
I solved this problem only updating the file bootstrap3-typeahead.min.js to the file in https://github.com/bassjobsen/Bootstrap-3-Typeahead/blob/master/bootstrap3-typeahead.min.js
I think most people can solve this way.