Twitter bootstrap typeahead (метод 'toLowerCase' из undefined)

Я пытаюсь использовать twitter bootstrap, чтобы получить производителей из моей базы данных.

Поскольку twitter bootstrap typeahead не поддерживает вызовы ajax, я использую эту вилку:

https://gist.github.com/1866577

На этой странице есть comment, в котором упоминается, как делать именно то, что я хочу сделать. Проблема в том, что когда я запускаю свой код, я продолжаю получать:

Uncaught TypeError: невозможно вызвать метод 'toLowerCase' из undefined

Я столкнулся с ошибкой и попробовал сменить файл jquery на оба с использованием мини-и неминифицированных, а также на один, размещенный в коде google, и я продолжал получать ту же ошибку.

В настоящее время мой код выглядит следующим образом:

$('#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) {

    }
});

в поле url я добавил

window.location.origin

чтобы избежать каких-либо проблем, как уже обсуждалось по другому вопросу

Кроме того, до того, как я использовал $.each(), а затем решил использовать $.map() в качестве рекомендуемого Томислава Марковского в аналогичном вопросе

У кого-нибудь есть идея, почему я продолжаю получать эту проблему?!

Спасибо

Ответ 1

Typeahead ожидает список строк в качестве источника

$('#manufacturer').typeahead({
    source : ["item 1", "item 2", "item 3", "item 4"]
})

В вашем случае вы хотите использовать его со списком объектов. Таким образом вам придется внести некоторые изменения, чтобы заставить его работать.

Это должно работать:

$('#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

В моем случае я получил эту точную ошибку, и оказалось, что версия Bootstrap, которую я использовал (2.0.4), не поддерживала передачу функции в настройку source.

Обновление до Bootstrap 2.1.1 устраняет проблему.

Ответ 3

ОБНОВЛЕНО/ПЕРЕСМОТРЕННЫЙ ВЗГЛЯД НА НОМЕР: Ошибка, о которой вы упомянули, "Не удалось вызвать метод" toLowerCase "из undefined" возникла у меня, когда я использовал оригинальное расширение Typeahead в бутстрапе, которое не поддерживает AJAX. (как вы уже нашли) Вы уверены, что исходное расширение typeahead не загружается, а не пересмотрено?

Я был успешно используя этот Gist of typehead, который является небольшим изменением по сравнению с тем, которое вы упомянули. Как только я переключился на этот Gist и подтвердил, что входные данные были хорошими (проверка того, что вход был строковым массивом в объекте JS, проблема исчезла.

Надеюсь, что это поможет


Оригинальный ответ:

Причина, по которой происходит ошибка, заключается в том, что значение, переданное в функцию matte-type, называется undefined. Это всего лишь побочный эффект реальной проблемы, которая возникает где-то между вашим входом и этой функцией сопряжения. Я подозреваю, что массив "производителей" имеет проблему. Сначала проверьте его, чтобы убедиться, что у вас есть допустимый массив.

// It appears your array constructor is missing ()
// try the following in your binding code:
var manufacturers = new Array();

Вот что я использую для привязки ввода к typeahead. Я подтвердил, что он работает с вашей модифицированной вилкой типа head.

Мой 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>

Мой обязательный код JavaScript:

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

В моем случае у меня были нулевые значения в моем исходном массиве, вызвавшие эту ошибку.

Упрощенный пример:

source : ["item 1", "item 2", null, "item 4"]

Ответ 5

Объекты вашего производителя не имеют свойства "name", вы должны изменить

property: 'name',

к

property: 'manufacturer',

Ответ 6

Пробовали ли вы использовать переменные сопоставления, например, пример ниже, вам нужно использовать это, когда у вас есть больше одного свойства в вашем объекте;

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

Я наткнулся на этот вопрос некоторое время назад. Я советую вам перепроверить конфигурацию, в которой вы включаете библиотеки typeahead (через main.js, app.js или config.js).

В противном случае вы можете перезаписать последнюю версию Bootstrap в свою библиотеку приложений.

Ответ 8

Попробуйте этот код:

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

});