Typeahead не работает, когда пользователь печатает очень быстро

Я использую typeahead, где при вводе его предложения отображаются в окне поиска, в то время как предложения поступают с сервера.

Он работает нормально, за исключением случаев, когда пользователь печатает очень быстро. Например, если мы вводим storm, отображаются записи. Когда я набираю одно и то же слово со скоростью, предложения не отображаются, пока я получаю данные в ответе. Я проверил, напечатав JSON прямо над полем, поэтому, когда я пишу storm быстро, он показывает JSON, но не показывает предложения ниже.

Вот html

<input type="text" ng-model="header.search"
    typeahead-on-select="searchClicked($item)"
    uib-typeahead="state as state.data.name for state in suggestions | filter:$viewValue | limitTo:8"
    typeahead-min-length="0" placeholder="Søg..." search-products>

search-products – это директива, используемая для трансляции значений поиска. Вот код директивы.

APP.directive('searchProducts', searchProducts);
function searchProducts($state) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            scope.$watch(attrs.ngModel, function(searchVal) {
                scope.$broadcast('searchTheProducts', searchVal);
            });
        }
    };
}

Вот вызов службы, где мы получаем данные.

$scope.$on('searchTheProducts', function(event, query) {
    if (query) {
        headerService.getSearchSuggestions(query).then(
            function(response) {
                $scope.suggestions = response;
            },
            function(err) {
                console.log('Error: ' + err);
            }
        );
    }
});

вот логика сервиса

  function getSearchSuggestions(query) {
    pendingRequests.cancelAll();
    var url = ApiBaseUrl + "/search/suggestions?query=" + query;
    var deferred = $q.defer();
    pendingRequests.add({
        url: url,
        canceller: deferred
    });

    pending = true;
    $http({
        method: "GET",
        url: url,
        timeout: deferred.promise
    }).then(
        function(successData) {

            deferred.resolve(successData.data.data);
        },
        function(err) {

            deferred.reject(err);
        }
    );
    return deferred.promise;
}

person naCheex    schedule 05.10.2016    source источник
comment
Не могли бы вы добавить <pre>{{header.search}} | {{suggestions|json}}</pre> на свою страницу и показать нам, что она выводит, когда вы быстро печатаете?   -  person Buh Buh    schedule 07.10.2016
comment
камень | [ { тип: продукт, данные: { название: пианино каменного века } }, { тип: отдел, данные: { название: диетическое питание каменного века } } ]   -  person naCheex    schedule 07.10.2016
comment
Я написал, что он показывает вывод, но в раскрывающемся списке ничего не отображается, когда я нажал клавишу Backspace, он внезапно отображается   -  person naCheex    schedule 07.10.2016
comment
Можете ли вы добавить часть кода (в серверной части), которая возвращает данные в вашу службу headerService. Между тем, что показывает консоль вашего браузера, когда uib-typeahead выполняет HTTP запросов по мере ввода?   -  person Ahmad Baktash Hayeri    schedule 09.10.2016
comment
вам нужно устранить дребезг ввода, аналогично typeahead-wait-ms="400", попробуйте сделать это при вызове API, используйте устранение дребезга, а не дроссель   -  person harishr    schedule 10.10.2016
comment
@entre nops :( Я пробовал   -  person naCheex    schedule 10.10.2016
comment
@AhmadBaktashHayeri ничего не отображается в консоли   -  person naCheex    schedule 10.10.2016
comment
@naCheex, можете ли вы добавить логику возврата данных с сервера в свой исходный пост?   -  person Ahmad Baktash Hayeri    schedule 10.10.2016
comment
@AhmadBaktashHayeri Пожалуйста, посмотрите, я обновил.   -  person naCheex    schedule 10.10.2016
comment
Можем ли мы предложить немного другой подход? без использования пользовательской директивы, чтобы определить, изменился ли ввод, и получить результаты в соответствии с ним, хотя шаблон проектирования останется прежним?   -  person ngCoder    schedule 10.10.2016
comment
@ Angular_10 Я попытался удалить пользовательскую директиву и использовать ngkeypress, но это не сработало.   -  person naCheex    schedule 10.10.2016


Ответы (3)


Я не думаю, что вам нужна пользовательская директива для запуска вызова $http для получения результатов всякий раз, когда изменяется ваше входное значение. Вместо этого вы можете сделать, как показано ниже.

<input type="text" ng-model="header.search"
    typeahead-on-select="searchClicked($item)"
    uib-typeahead="state as state.data.name for state in suggestions($viewValue) | filter:$viewValue | limitTo:8"
    typeahead-min-length="0" placeholder="Søg..." >

В вашем JS-контроллере вы можете написать функцию $scope.suggestions() для получения новых результатов по типу запроса.

var app = angular.module('plunker', ['ui.bootstrap']);

    app.factory('dataProviderService', ['$http', function($http) {
        var factory = {};
        factory.getCities = function(input) {
            //I've used google api to fetch cities ..we can place our service call here..
          return  $http.get('//maps.googleapis.com/maps/api/geocode/json', {
                params: {
                    address: input,
                    sensor: false
                }
            }).then(function(response) {//on success the results can be further processed as required..
                return response.data.results.map(function(item) {
                    return item.formatted_address;
                });
            });

        };

        return factory;
    }]);

     app.controller('TypeaheadCtrl', ['$scope', '$log','$http', 'dataProviderService', function($scope, $log,$http, dataProviderService) {
            $scope.suggestions= function(viewValue) {
                //you can call your own service call via a factory 
             return   dataProviderService.getCities(viewValue);

            };

        }]);

Вот DEMO рабочего образца для вышеупомянутого способа, надеюсь, это поможет вам. При таком подходе, независимо от того, насколько быстро вы печатаете, вы всегда будете мгновенно получать свежие результаты.

person ngCoder    schedule 10.10.2016
comment
Как предложение будет заполняться по конкретному запросу? - person naCheex; 10.10.2016
comment
всякий раз, когда вы печатаете, он автоматически извлекает результаты из $scope.suggestions, поэтому, если ваш служебный вызов достаточно хорош для обработки любого типа ввода и выдачи результатов, вы всегда будете получать результаты в виде впереди. Проверьте плункер и попробуйте, набрав что-нибудь. - person ngCoder; 10.10.2016
comment
@naCheex рад, что помог тебе! - person ngCoder; 14.10.2016

Я не совсем уверен, почему у вас есть:

angular.forEach(response, function(val, key) {
  $scope.suggestions= response;
});

Если response равно 100 элементам, то по какой-то причине вы каждый раз обновляете $scope.suggestions, и это может вызывать проблему. Просто удалите angular.forEach и вместо него просто используйте $scope.suggestions = response.

person Ahmed Nuaman    schedule 07.10.2016
comment
Да, я пробовал без foreach, но все равно ведет себя так же. В первый раз, когда я пишу 3,4 символа быстро, он ничего не показывает, а когда я печатаю его с нормальной скоростью, он работает нормально. - person naCheex; 07.10.2016
comment
А в вашу службу делается запрос? - person Ahmed Nuaman; 07.10.2016
comment
да, и он получает ответ, я проверил, показав его чуть выше раскрывающегося списка. - person naCheex; 07.10.2016

Вы можете использовать атрибут typeahead-wait-ms, чтобы не выполнять запросы при каждом ударе:

<input typeahead-wait-ms="50">
person Buh Buh    schedule 07.10.2016