AngularUI-Bootstrap Typeahead не может прочитать `length` Свойство `undefined`

Я получаю следующую ошибку, когда пытаюсь получить значения типа из AngularUI-Bootstrap, используя обещание.

TypeError: Cannot read property 'length' of undefined
  at http://localhost:8000/static/js/ui-bootstrap-tpls-0.6.0.min.js:1:37982
  at i (http://localhost:8000/static/js/angular.min.js:79:437)
  at i (http://localhost:8000/static/js/angular.min.js:79:437)
  at http://localhost:8000/static/js/angular.min.js:80:485
  at Object.e.$eval (http://localhost:8000/static/js/angular.min.js:92:272)
  at Object.e.$digest (http://localhost:8000/static/js/angular.min.js:90:142)
  at Object.e.$apply (http://localhost:8000/static/js/angular.min.js:92:431)
  at HTMLInputElement.Va.i (http://localhost:8000/static/js/angular.min.js:120:156)
  at HTMLInputElement.x.event.dispatch (http://localhost:8000/static/js/jquery-1.10.2.min.js:5:14129)
  at HTMLInputElement.v.handle (http://localhost:8000/static/js/jquery-1.10.2.min.js:5:10866) 

Мой тег HTML:

<input type="text" class="form-control" id="guestName" ng-model="name" typeahead="name for name in getTypeaheadValues($viewValue)">

Моя функция getTypeaheadValues делает следующее:

$scope.getTypeaheadValues = function($viewValue)
{
    // return ['1','2','3','4'];

    $http({
        method: 'GET',
        url: 'api/v1/person?name__icontains=' + $viewValue
    }).error(function ($data) {
        console.log("failed to fetch typeahead data");
    }).success(function ($data) {
        var output = [];
        $data.objects.forEach(function (person)
        {
            output.push(person.name);
        });
        console.log(output);
        return output;
    });
}

Я не понимаю, на что AngularUI-Bootstrap жалуется как на неопределенность. Если я удалю комментарий к самому верхнему return, значения будут отображаться нормально. Выход console.log в success также возвращает все значения, которые я ожидаю в массиве.

Что мне не хватает, чтобы AngularUI-Bootstrap не видел возвращаемый массив?


person Nicholas Pappas    schedule 22.10.2013    source источник


Ответы (3)


Эта проблема была двоякой.

Во-первых, я не возвращал событие обещания (вызов $http). Отсутствие оператора return (как указывает @tobo) напрямую вызывало ошибку. Мне нужно было вернуть обещание, а не массив.

Во-вторых, мне нужно использовать .then, а не .success для AngularUI-Bootstrap, чтобы получить результаты.

Я столкнулся со следующим вопросом: https://stackoverflow.com/questions/15930339/how-to-tie-angular-uis-typeahead-with-a-server-via-http-for-server-side-optimi

Который обновил мой вызов функции до следующего:

$scope.getTypeaheadValues = function($viewValue)
{
    return $http({
        method: 'GET',
        url: 'api/v1/person?name__icontains=' + $viewValue
    }).then(function ($response) {
        var output = [];

        console.log($data);

        $response.data.objects.forEach(function (person)
        {
            output.push(person.name);
        });

        console.log(output);
        return output;
    });
}
person Nicholas Pappas    schedule 22.10.2013

$scope.getTypeaheadValues ​​не возвращает никакого массива. Он возвращает null, потому что ваш оператор return находится в функции обратного вызова «успех», которая называется асинхронностью.

Возможно, это сработает:

$scope.getTypeaheadValues = function($viewValue)
{    
    var output = [];
    $http({
        method: 'GET',
        url: 'api/v1/person?name__icontains=' + $viewValue
    }).error(function ($data) {
        console.log("failed to fetch typeahead data");
    }).success(function ($data) {            
        $data.objects.forEach(function (person)
        {
            output.push(person.name);
        });
        console.log(output);        
    });
    return output;
}
person T.Riemer    schedule 22.10.2013
comment
Но асинхронный вызов $http не завершится, заполнив массив output, к моменту вызова оператора return. Хотя это решение устраняет ошибку, это всегда пустой массив, поскольку он никогда не заполняется вовремя. - person Nicholas Pappas; 22.10.2013
comment
Я разобрался. Смотрите мой ответ на вопрос. Ваш ответ заставил меня задуматься в правильном направлении - спасибо. - person Nicholas Pappas; 22.10.2013
comment
Погуглил немного. Кажется, вы можете просто передать обещание для ввода. - person T.Riemer; 22.10.2013
comment
Как сделать то же самое с $resource вместо $http? - person Stephane; 04.09.2014
comment
Вот как это сделать с кодом $resource: return TechnologyService.search($scope.searchTerm, function(data) { return data.content; }); - person Stephane; 04.09.2014

$scope.getTypeaheadValues = function($viewValue)
{
    var someOutput="";//return something

    $http({
        method: 'GET',
        url: 'api/v1/person?name__icontains=' + $viewValue
    }).error(function (data) {
        console.error(data);
    }).success(function (data) {
        console.log(data);//Do whatever you want 
    });
return someOutput;

}

// Оператор возврата отсутствует

person Ankit Shukla    schedule 16.03.2015